【问题标题】:Differences in calculation of adler32 rolling checksum - pythonadler32滚动校验和的计算差异 - python
【发布时间】:2012-03-30 18:08:34
【问题描述】:

在计算运行校验和时需要说明。

假设我有这样的数据。

data = 'helloworld'

假设块大小为 5,我需要计算运行校验和。

>>> zlib.adler32('hello')
103547413
>>> zlib.adler32('ellow')
105316900

根据 Python 文档(python 版本 2.7.2)

zlib.adler32(data[, value])

"计算数据的 Adler-32 校验和。(Adler-32 校验和几乎是 与 CRC32 一样可靠,但计算速度更快。)如果 value 存在,它被用作校验和的起始值; 否则,使用固定的默认值。这允许计算一个 对多个输入的串联运行校验和。”

但是当我提供这样的东西时,

>>> zlib.adler32('ellow', zlib.adler32('hello'))
383190072

输出完全不同。

我尝试创建一个自定义函数来生成 rsync 算法中定义的滚动校验和。

def weakchecksum(data):
    a = 1
    b = 0

    for char in data:
        a += (ord(char)) % MOD_VALUE
        b += a % MOD_VALUE



    return (b << 16) | a



def rolling(checksum, removed, added, block_size):
    a = checksum
    b = (a >> 16) & 0xffff
    a &= 0xffff

    a = (a - ord(removed) + ord(added)) % MOD_VALUE
    b = (b - (block_size * ord(removed)) + a) % MOD_VALUE

    return (b << 16) | a

这是我通过运行这些函数得到的值

Weak for hello: 103547413
Rolling for ellow: 105382436
Weak for ellow: 105316900

如您所见,我的滚动校验和和 python 的实现在价值方面存在巨大差异。

我在计算滚动校验和时哪里出错了? 我是否正确利用了 python 的 adler32 函数的滚动属性?

【问题讨论】:

    标签: python adler32


    【解决方案1】:

    我认为您在测试中错误地计算了 adler32 值:

    >>> import zlib
    >>> zlib.adler32("helloworld")
    389415997
    >>> zlib.adler32("world",zlib.adler32("hello"))
    389415997
    

    【讨论】:

    • 谢谢。但是,我想我正在寻找滚动校验和的差异。在您的情况下,我得到的是“世界”的校验和,而我感兴趣的是,使用“你好”的校验和计算“黄”的校验和。两者之间的区别在于删除了“h”并添加了“w”。如果我不清楚,请告诉我。
    【解决方案2】:

    adler32() 函数不提供“滚动”功能。文档正确地使用了“运行”(而不是“滚动”)这个词,这意味着它可以以块的形式计算 adler32,而不是一次全部计算。您需要编写自己的代码来计算“滚动”adler32 值,这将是数据上滑动窗口的 adler32。

    【讨论】:

      【解决方案3】:

      顺便说一句,您的 def rolling() 是正确的,至少对于模结果的符号具有除数符号的 Python 来说是正确的。它可能不适用于其他语言,例如在 C 语言中,% 的结果符号要么是被除数的符号,要么是由实现定义的。

      您可以通过考虑在每个步骤中与模 65521 相差多远来提高算法的效率,或者将 % 替换为 if 和 65521 的加法或减法,或者使用足够大的数据类型让它运行同时并弄清楚您可以在总和上获得 % 以避免溢出的频率。同样,请注意负股息的百分比。

      【讨论】:

      • 感谢您的额外 cmets,马克。
      • 我尝试使用素数 65521 并在我的滚动校验和过程实现中出现计算错误(更改已检测到或未检测到)。如果我使用 2^16,一切都很好。我希望我能稍后再回到这个问题,并排除编程错误的可能性,同时带来一些关于该主题的有用信息。
      【解决方案4】:

      这里是工作函数。请注意 MOD 是在哪一步计算的。

      def myadler32(data):
        a = 1
        b = 0
        for c in data:
            a += c
            b += a
        a %= MOD_ADLER
        b %= MOD_ADLER
        return b<<16 | a
      

      【讨论】:

        【解决方案5】:

        在你的“滚动”方法中,

        b = (b - (block_size * ord(removed)) + a) % MOD_VALUE
        

        应该是

        b = (b - (block_size * ord(removed)) + a - 1) % MOD_VALUE
        

        根据维基百科对adler32算法的解释,可以看到:

        A = 1 + D1 + D2 + ... + Dn (mod 65521)
        B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)
          = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n (mod 65521)
        
        Adler-32(D) = B × 65536 + A
        

        当我们滚动校验和时,我们将有方程式:

        A1 = (1 + D2 + D3 + … + Dn + Dn+1)(mod 65521)
        = (1 + D1 + D2 + D3 + … + Dn) – D1 + Dn+1(mod 65521)
        = A – D1 + Dn+1(mod 65521)
        B1 = (1 + D2) + (1 + D2 + D3) + … + (1 + D2 + D3 + … + Dn + Dn+1)(mod 65521)
        = (1 + D1) – D1 – 1 + (1 + D1 + D2) – D1 + ... +(1 + D1 + D2 + … + Dn) – D1 + (1 + D1 + D2 +      … + Dn + Dn+1) – D1(mod 65521)
        = B – nD1 – 1 + A1 + D1 – D1(mod 65521)
        = B – nD1 + A1 – 1(mod 65521)
        

        【讨论】:

          猜你喜欢
          • 2010-11-21
          • 1970-01-01
          • 2017-04-20
          • 2017-03-09
          • 2010-12-18
          • 2021-04-05
          • 2018-07-21
          • 2020-07-02
          • 2014-03-02
          相关资源
          最近更新 更多