2

この変換はオリジナルから正しいですか?

uint8_t fletcher8( uint8_t *data, uint8_t len )
{
    uint8_t sum1 = 0xff, sum2 = 0xff;

    while (len) {
            unsigned tlen = len > 360 ? 360 : len;
            len -= tlen;
            do {
                    sum1 += *data++;
                    sum2 += sum1;
                    tlen -= sizeof( uint8_t );
            } while (tlen);
            sum1 = (sum1 & 0xff) + (sum1 >> 4);
            sum2 = (sum2 & 0xff) + (sum2 >> 4);
    }
    /* Second reduction step to reduce sums to 4 bits */
    sum1 = (sum1 & 0xff) + (sum1 >> 4);
    sum2 = (sum2 & 0xff) + (sum2 >> 4);
    return sum2 << 4 | sum1;
    }

オリジナル:

uint32_t fletcher32( uint16_t *data, size_t len )
{
    uint32_t sum1 = 0xffff, sum2 = 0xffff;

    while (len) {
            unsigned tlen = len > 360 ? 360 : len;
            len -= tlen;
            do {
                    sum1 += *data++;
                    sum2 += sum1;
                    tlen -= sizeof( uint16_t );
            } while (tlen);
            sum1 = (sum1 & 0xffff) + (sum1 >> 16);
            sum2 = (sum2 & 0xffff) + (sum2 >> 16);
    }
    /* Second reduction step to reduce sums to 16 bits */
    sum1 = (sum1 & 0xffff) + (sum1 >> 16);
    sum2 = (sum2 & 0xffff) + (sum2 >> 16);
    return sum2 << 16 | sum1;
    }

len は 8 になります。

data には data[] (1 - 8) の入力が含まれます。

実際、次の行をどうすればよいかわかりません: unsigned tlen = len > 360 ? 360 : レン;

たぶん -> int8_t tlen = len > 255 ? 255: レン;

4

3 に答える 3

2

tlenこの値の計算方法

実際、次の行をどうすればよいかわかりません: unsigned tlen = len > 360 ? 360 : レン;

その行は、このウィキペディアのセクションの古いバージョンから来ているようです。現在は 359 に変更されており、その理由はトークページで説明されています。この数は、満足する最大の数nであるため、16 ビット エンティティの合計にのみ適用されます。

n ( n +5)/2 × (2 16 −1) < 2 32

言い換えれば、これはモジュロ削減を実行せずにブロックを追加できる最大回数であり、それでもuint32_t. 4 ビットのデータ ワードと 8 ビットのアキュムレータの場合、対応する値は 4 になり、次の式を使用して計算されます。

n ( n +5)/2 × (2 4 −1) < 2 8

したがって、データ サイズを変更する場合は、その行を変更する必要があります。より大きなデータ型を使用して合計を保持するようにコードを変更することもできます。これにより、リダクション前により多くのブロックが合計されます。ただし、その場合、ループ内で複数の削減ステップが必要になる場合があります。

たとえば、uint32_tforsum1とを使用する場合sum2、オーバーフローの危険が生じる前に 23927 ニブルを合計できますが、その後、元のアゴリズムのように、これを を介しsum1 = (sum1 & 0xf) + (sum1 >> 4)て範囲に煮詰めるには、フォームを最大 7 回削減する必要があります。それ。のように書いた方が効率的かもしれません。その場合、範囲を 1 から 15 から 0 から 14 に戻し、合計を 0 に初期化し、削減を として書き込むことさえできます。他の範囲を使用する実装との互換性が必要でない限り。10x1e(sum1 - 1)%0xf + 1sum1 %= 0xf

于 2012-11-21T17:04:58.187 に答える
1

0xFF ではなく全体に 0xF マスクが必要だと思います。32 ビットは 16 ビット マスク、32 の半分を使用し、8 ビットは 8 の半分ではない 8 ビット マスクを使用し、4 ビットは 8 の半分です。

uint8_t fletcher8( uint8_t *data, uint8_t len )
{
    uint8_t sum1 = 0xf, sum2 = 0xf;

    while (len) {
        unsigned tlen = len > 360 ? 360 : len;
        len -= tlen;
        do {
                sum1 += *data++;
                sum2 += sum1;
                tlen -= sizeof( uint8_t );
        } while (tlen);
        sum1 = (sum1 & 0xf) + (sum1 >> 4);
        sum2 = (sum2 & 0xf) + (sum2 >> 4);
    }
    /* Second reduction step to reduce sums to 4 bits */
    sum1 = (sum1 & 0xf) + (sum1 >> 4);
    sum2 = (sum2 & 0xf) + (sum2 >> 4);
    return sum2 << 4 | sum1;
}

それ以外の場合は、フレッチャーではなく、別のチェックサムを作成しています。たとえば、sum1 は、1 の補数チェックサムと呼ばれるものを実行しています。基本的に、以前は16ビット、あなたの場合は4ビットで、キャリービットが追加されるチェックサムです。インターネットプロトコルで使用されると、パケット全体のチェックサムを計算する必要なく、パケットを簡単に変更できます。既存のチェックサムに対して変更のみを加算および減算します。

追加のリダクション ステップはコーナー ケース用です。sum1 += *data = 0x1F の結果が 4 ビット スキームを使用している場合、キャリー ビットの追加は 0x01 + 0x0F = 0x10 であり、そのキャリー ビットを元に戻す必要があります。ループ 0x01 + 0x00 = 0x01 の外側でも同様です。それ以外の場合は、ループの合計の外側にゼロが追加されます。アーキテクチャによっては、 if(sum1&0x10) sum1=0x01; のようなものを使用すると、より高速に実行できる場合があります。より多くの指示が必要なずる賢い追加よりも。

キャリービットが追加された単なるチェックサム以上のものになるのは、2つが組み合わされる最後のステップです。たとえば、32 ビットのフレッチャーを 16 ビットのチェックサムとしてのみ使用すると、時間を無駄にします。結果の下位 16 ビットは、キャリー ビットが追加されたストック チェックサムにすぎず、特別なことは何もありません。sum2 は、sum1 チェックサムの累積であるため、興味深い数値です (sum1 はデータの累積、sum2 はチェックサムの累積です)。

于 2012-01-19T14:59:52.687 に答える
0

元のバージョンでは、sum1、sum2 は 32 ビットです。そのため、後でビットがシフトします。あなたの場合、sum1、sum2を8ビットと宣言しているので、ビットシフトは意味がありません。

于 2012-01-19T11:23:25.310 に答える