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:长度;

该行似乎来自此 Wikipedia 部分旧版本。现在它已更改为 359,并在讨论页上解释了理由。该数字仅适用于对 16 位实体求和,因为它是满足的最大数字n

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

换句话说,这是您可以在不执行模归约的情况下添加块的最大次数,并且仍然避免溢出uint32_t. 对于 4 位数据字和 8 位累加器,对应的值为 4,计算公式为

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

因此,如果您更改数据大小,则必须修改该行。您还可以更改代码以使用更大的数据类型来保持其总和,从而在减少之前对更多块求和。但在这种情况下,您可能需要在循环内进行不止一个归约步骤。

例如,如果您使用uint32_tforsum1sum2,那么您可以在溢出危险之前对 23927 个半字节求和,但在此之后,您将需要最多 7 次减少形式sum1 = (sum1 & 0xf) + (sum1 >> 4)来将其归结为范围1通过0x1e,就像您的原始算法一样它。将其写为(sum1 - 1)%0xf + 1. 在这种情况下,您甚至可以将范围从 1 到 15 更改回 0 到 14,将总和初始化为 0 并将减少写为sum1 %= 0xf. 除非您需要与使用其他范围的实现兼容。

于 2012-11-21T17:04:58.187 回答
1

我认为你需要 0xF 掩码而不是 0xFF。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;
}

否则,您将创建一个不同的校验和,而不是 Fletcher。例如 sum1 正在执行我认为所谓的补码校验和。基本上它是 16 位在前和 4 位在你的情况下,校验和,其中进位位被添加回来。在互联网协议中使用使得修改数据包非常容易,而无需计算整个数据包的校验和,你可以仅对现有校验和添加和减去更改。

额外的减少步骤是针对极端情况,如果 sum1 += *data = 0x1F 使用四位方案的结果,则进位位的添加为 0x01 + 0x0F = 0x10,您需要将进位位添加回在循环0x01 + 0x00 = 0x01之外也是如此。否则,循环和之外的加零。根据您的架构,您可能会使用类似 if(sum1&0x10) sum1=0x01; 的方法更快地执行。比可能需要更多指令的狡猾添加的东西。

它不仅仅是添加进位的校验和,而是将两者结合起来的最后一步。例如,如果您仅使用 32 位 fletcher 作为 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 回答