Fletcher32:维基百科的限制是360错了?

时间:2014-02-01 10:21:09

标签: java optimization hashcode checksum

关于Fletcher校验和的维基百科文章(目前)对Fletcher 32说the sums need to be reduces after 360 steps。但是,根据我的测试,在720步之后减少就足够了。维基百科的360限制是错误的,还是我在测试中犯了错误?

任何其他可能优化的奖励积分:-)除了硬编码限制外。

我的测试用例(Java,但同样适用于C或C#):

public static void main(String... args) {
    byte[] data = new byte[2 * 1024];
    Arrays.fill(data, (byte) 255);
    for (int limit = 1; limit <= 721; limit++) {
        System.out.println("Test limit " + limit);
        for (int i = 0; i < data.length; i += 2) {
            if (getFletcher32(data, i, 1) != getFletcher32(data, i, limit)) {
                System.out.println("Stop at limit=" + limit + " index=" + i);
                return;
            }
        }
    }
}

// bytes: the data
// length: the number of bytes (must be an even number)
// limit: when to reduce the sums (only used for testing)
static int getFletcher32(byte[] bytes, int length, int limit) {
    int s1 = 0xffff, s2 = 0xffff;
    for (int i = 0; i < length;) {
        for (int end = Math.min(i + limit, length); i < end;) {
            int x = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
            s2 += s1 += x;
        }
        s1 = (s1 & 0xffff) + (s1 >>> 16);
        s2 = (s2 & 0xffff) + (s2 >>> 16);
    }
    s1 = (s1 & 0xffff) + (s1 >>> 16);
    s2 = (s2 & 0xffff) + (s2 >>> 16);
    return (s2 << 16) | s1;
}

测试打印:

Test limit 1
Test limit 2
...
Test limit 720
Test limit 721
Stop at limit=721 index=721

意味着对于限制1到720的结果是相同的,并且只有限制721,校验和是不同的(意思是,它是不正确的)。

2 个答案:

答案 0 :(得分:1)

我发现我的旧答案非常错误,所以我写了这个简单的循环来检查int溢出:

long s1 = 0xffff, s2 = 0xffff;
for (int n=0; ; ++n) {
    final int a = 0xff;
    final int b = 0xff;
    final int x = (a << 8) | b;
    s2 += s1 += x;
    System.out.format("%4d %08X %08X\n", n, s1, s2);
    if ((s2 & 0xFFFFFFFFL) != s2) break;
}

输出以

结尾
358 0167FE98 FDD3022C
359 0168FE97 FF3C00C3
360 0169FE96 100A5FF59

向我们展示了我们必须在第360次迭代之前停止,以便s2不会溢出。


所提出的算法有一个区别。这条线

return (s2 << 16) | s1;

应该阅读

return (s2 << 16) | (s1 & 0xffff);

原始类型为uint16_t,但这并不重要,因为s1很小。

答案 1 :(得分:1)

我现在意识到自己的错误,并且看到维基百科我的实施都是正确的......

原因是,维基百科文章使用了360个(每个字两个字节)的限制,而我的实现使用了720 字节的限制。

至于优化:可能最后的缩减步骤可能会略微简化,但这不会有太大变化。