使用Cython处理大整数时出现OverflowError错误

18

Python 3.4、Windows 10、Cython 0.21.1

我正在使用Cython将此函数编译为C语言。

def weakchecksum(data):
   """
   Generates a weak checksum from an iterable set of bytes.
   """
   cdef long a, b, l
   a = b = 0
   l = len(data)
   for i in range(l):
       a += data[i]
       b += (l - i)*data[i]

   return (b << 16) | a, a, b

产生此错误的代码如下: "OverflowError: Python int too large to convert to C long"

我还尝试将它们声明为无符号长整型。使用哪种类型可以处理非常大的数字?如果它太大了,无法转换为C语言的长整型,是否有任何解决办法?


1
相同的错误,导致该错误的数字是2891688164113197。 - user2682863
1
是的,我考虑过了。我正在使用Cython加速一些代码,并希望避免创建会增加开销的特殊类。 - user2682863
2891688164113197 可以放入 int64_t 中,你应该使用它。你尝试过使用 from libc.stdint cimport int64_t 吗? - user1415946
使用这种技术,数据越长,你需要的数字就越大,除非你有一个动态的“大整数”类,否则最终会溢出任何存储。我同意@shaunc的观点。校验和通常是数据的哈希值。您是否考虑过简单的校验和算法或md5哈希?它们是否适合您的需求? - cod3monk3y
我考虑使用不同的校验和算法,这个算法是来自rsync算法的一个函数,专门为了速度而设计。它为文件的每个块创建一个校验和。我认为用md5替换会带来显著的性能成本,并且可能会使使用cython的好处无效化。我会去检查一下。 - user2682863
显示剩余7条评论
2个回答

13

cython编译pyx文件到C,因此它依赖于底层的C编译器。

C中整数类型的大小因平台和操作系统而异,并且C标准没有规定确切的实现方式。

但是,有一些事实上的实现约定。

Windows 32位和64位都使用4个字节(32位)作为intlong,使用8个字节(64位)作为long long。 Win32和Win64之间的区别在于指针的大小(Win32为32位,Win64为64位)。(请参见来自MSDN的数据类型范围)。

Linux使用另一种模型:int 对于linux-32和linux-64都是32位,long long始终是64位。 long和指针不同:在linux-32上是32位,在linux-64上是64位。

长话短说:如果您需要在不同平台上使用的整数类型的最大容量,请使用long long(或unsigned long long)。

long long的数据范围为[-9223372036854775808, 9223372036854775807]

如果您需要任意精度的数字,则有GMP库 - 高精度算术的事实标准。 Python有一个称为gmpy2 的包装器。


5

如果您确保您的计算是在c语言中进行的(例如,将i声明为long,并将数据元素放入cdefed变量或在计算之前转换它),则不会出现此错误。但实际结果可能会因平台而异,取决于生成的精确汇编代码和溢出处理的结果。正如@cod3monk3y所指出的那样,有更好的算法可用于此(请查看“简单校验和”链接)。


1
所以我将“i”添加到了cdef语句中并重新运行了它。仍然得到相同的错误。还尝试了cdef long long a、b、l、i。 - user2682863
尝试使用 cdef long d ...(并在循环中)d = data[i] 或者直接在计算中使用 d(或者使用 <<long>>data[i])。您可以使用标志编译以查看带有 Python 行注释的实际 c 代码生成 - 当没有涉及到 Python 变量时,您应该看到计算是一个纯 c 表达式。(注意我无法在标记中正确拼写转换) - shaunc
太完美了。我已经放弃得到这个答案了。你真是个天才。给那些未来阅读这篇文章的人提供一个提示。我声明了cdef long a,b,l,i,d,并将每个对data [i]的引用更改为d。 - user2682863

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接