【问题标题】:Why does my rolling adler32 checksum not work in go? (modulo arithmetic)为什么我的滚动 adler32 校验和在 go 中不起作用? (模算术)
【发布时间】:2017-04-20 11:38:36
【问题描述】:

我正在实施 rolling 版本的 adler32 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 核心库)。

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

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

【问题讨论】:

  • 你的减法正在回绕。
  • 你将如何修复代码?
  • 如果您在计算 b 时应用 32 位掩码,您会在 Python 代码中得到相同的差异 (0xe10000),如下所示:b = ((b - (n*leave) - 1 + a) &amp; 0xffffffff) % MOD

标签: python go checksum modulo adler32


【解决方案1】:

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

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?

【讨论】:

    【解决方案2】:

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

    当从较小的无符号数中减去无符号数时,您会得到一个巨大的无符号数,它在除法时给出的余数与小的负差不同。换行时,实际上是在添加 232。 232 mod 65521 是 225,或 0xe1,这就是为什么您会在 b 中看到这种差异。 b 计算更可能结束,但 a 也可能发生这种情况,如果 a 在该步骤恰好非常小。

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

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

    【讨论】:

    • 您还需要考虑python之间对负模除数的不同处理并考虑在内。 play.golang.org/p/R87XWewRPY(忽略 n*leave 溢出)
    • "如果 n*leave 大到足以包装正在使用的整数类型,两种语言的代码都会给出错误的结果。" - Python 使用任意精度的整数,因此在 Python 中溢出不是问题。
    • @user2357112 谢谢。解决了这个问题。
    • 哇,校验和作者本人的回答!非常感谢您的清晰解释。
    • 为了确保n*leave不换行,我想我可以用n*leave % MOD == n%MOD*leave替换它,这和在整个操作之前做n%=MOD是一样的。
    猜你喜欢
    • 2012-03-30
    • 1970-01-01
    • 2010-11-21
    • 2017-03-09
    • 2013-08-29
    • 2020-07-02
    • 2021-08-12
    • 2012-01-15
    • 2014-03-02
    相关资源
    最近更新 更多