为什么我的滚动adler32校验和不起作用? (模运算)

时间:2016-12-05 23:14:31

标签: python go checksum modulo adler32

我正在逐步实施rollingadler32 checksum版本。

answer有助于仔细检查我的数学。但是我正在努力在golang中正确实现它。

我写了以下代码:

func roll(adler, n, leave, enter uint32) uint32 {
    a := adler & 0xffff
    b := adler >> 16

    a = (a + enter - leave) % MOD
    b = (b - n*leave - 1 + a) % MOD
    return b<<16 | a
}

它在各种输入上测试了它并且工作正常,直到我决定在随机数据上运行它。这是一个sample,它不起作用(我发现其中有几个)。

令我困惑的是,python中的相同代码完全适用于这些输入:

def roll(adler, n, leave, enter):
    a = adler & 0xffff
    b = adler >> 16

    a = (a + enter - leave) % MOD
    b = (b - n*leave - 1 + a) % MOD
    return b<<16 | a

为了更好的衡量,我包括proof这在python中有效。请注意,python校验和与go校验和的非滚动版本匹配(该部分直接来自go核心库)。

我在所有其他有问题的样本上研究了我的结果,发现我从不在校验和的最低有效位(&#34; a&#34;位)上犯了错误。此外,错误始终相同,等于0xe10000。我怀疑如何处理uint32整数上的模运算是造成这种情况的原因。

发生了什么以及如何修复我的代码?

2 个答案:

答案 0 :(得分:4)

Python中的整数已签名。您声明golang版本中的所有整数都是无符号的。这就是区别。

当从较小的无符号数中减去无符号数时,会得到一个巨大的无符号数,它在除法上给出不同的余数而不是小的负差。当你换行时,你实际上是在添加2 32 。 2 32 mod 65521是225,或0xe1,这就是为什么你会在b看到这种差异的原因。它更有可能包含b计算,但a也可能发生,如果a在该步骤恰好很小。

根据@samgak的评论,您还必须担心不同语言中%运算符的定义是否有符号值。因此,在执行MOD之前,跨越不同约定的解决方案是通过在必要时添加尽可能多的% MOD来使值为正。对于a,只需添加MOD即可。对于b,请添加(1 + n * leave / MOD) * MOD

注意确保中间值不会溢出。如果n*leave足够大以包装正在使用的整数类型,则go中的代码可能会产生错误的结果。

答案 1 :(得分:0)

我不知道去,但这里有一些可能性:

b := adler >> 16 change to b := (adler >> 16) & 0xffff

b = (b - n*leave - 1 + a) % MOD ... what happens if expression in () is negative?

return b<<16 | a ... check operator precedence; (b<<16)|a or b<<(16|a) ?

32-bit machine or 64-bit?