使用Python C API将Python中的函数移植到C时遇到问题

使用Python C API将Python中的函数移植到C时遇到问题,python,algorithm,checksum,Python,Algorithm,Checksum,我在Python中有一个校验和函数: def checksum(data): a = b = 0 l = len(data) for i in range(l): a += ord(data[i]) b += (l - i)*ord(data[i]) return (b << 16) | a, a, b def校验和(数据): a=b=0 l=len(数据) 对于范围(l)中的i: a+=ord(数据[i]) b+=

我在Python中有一个校验和函数:

def checksum(data):
    a = b = 0
    l = len(data)
    for i in range(l):
        a += ord(data[i])
        b += (l - i)*ord(data[i])

    return (b << 16) | a, a, b
def校验和(数据):
a=b=0
l=len(数据)
对于范围(l)中的i:
a+=ord(数据[i])
b+=(l-i)*ord(数据[i])

返回(b我猜您的局部变量中存在某种溢出。可能b会变大。只需出于调试目的转储值,您就应该知道这是否是问题所在。正如您所提到的,出于性能原因,您正在移植该方法。您检查过psyco吗?可能足够快且更容易。还有更多其他问题需要解决ols将python代码的一部分实时编译为C,但我脑子里没有这些名称。

我建议原始的校验和函数是“不正确的”。为校验和返回的值大小不限(对于任何给定的MB大小,可以构造一个校验和至少为该大小的输入)。如果我的计算是正确的,那么对于小于260 MB的输入,该值可以适合64位,对于小于4096字节的任何输入,
b
可以适合整数。现在,我可能对该数字不感兴趣,但这意味着对于较大的输入,这两个函数的工作方式肯定不同

要将第一个函数转换为C,需要将
b
C
保留为Python整数,并将最后一个计算作为Python表达式执行。不过,这可以改进:

  • 您可以使用C
    long-long
    变量来存储中间和,并在一定次数的迭代后将其添加到Python整数中。如果迭代次数为
    n
    ,则
    a
    的最大值为
    n*255
    ,而
    b
    的最大值为
    len(数据)*n*255
    。当将它们存储在C
    long
    变量中时,请尝试将它们保存在
    2**63-1
  • 您可以使用
    long long
    而不是
    unsigned long
    ,并在调试模式下每次出现负值时引发
    RuntimeError
另一个解决方案是通过使用
a&0xffffffffffffffffff
b&0xffffffffffffffff
将Python限制为64位


最好的解决方案是使用另一种校验和,如
binascii.crc32

我应该在问题中提到这一点,但此函数用于“滚动”对应的,可以输入'a'和'b'以及删除和添加的字节,以基于上一个字节快速计算校验和,就像在rsync中一样。我不知道这是否会有任何区别,但我将尝试在Python对象中执行计算,看看是否有区别。我同意@Rosh的评估:您的a和b值是开的递增,它们将无限增长。算法从何而来?你确定你已经用Python正确地表达了它吗?它来自这篇文章:我相信校验和算法来自rsync算法的论文:你所指的算法明确提到mod2^16算法。你需要在你的ython。我可以这样做。我还发现了我的另一个问题——我需要使用无符号char而不是签名。这是一个溢出。如果你这样做是为了速度(而不是学习),考虑使用Cython或Heavy皮肤。
static PyObject *
checksum(PyObject *self, PyObject *args)
{
    int i, length;
    unsigned long long a = 0, b = 0;
    unsigned long long checksum = 0;
    char *data;

    if (!PyArg_ParseTuple(args, "s#", &data, &length)) {
        return NULL;
    }

    for (i = 0; i < length; i++) {
        a += (int)data[i];
        b += (length - i) * (int)data[i];
    }

    checksum = (b << 16) | a;
    return Py_BuildValue("(Kii)", checksum, (int)a, (int)b);
}