【问题标题】:OverflowError occurs when using cython with a large int使用具有大 int 的 cython 时发生溢出错误
【发布时间】:2014-11-12 01:42:03
【问题描述】:

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

产生此错误: “溢出错误:Python int 太大而无法转换为 C long”

我也尝试将它们声明为无符号长整数。我用什么类型来处理非常大的数字?如果它对于 c 长来说太大了,有什么解决方法吗?

【问题讨论】:

  • cdef long long 怎么样?
  • 同样的错误,导致它的数字是 2891688164113197
  • 考虑制作一个大整数类?它将是一个包含数字的链表
  • 是的,我考虑过,我正在使用 cython 来加速一些代码,并希望避免创建会增加开销的特殊类
  • 在 gcc 上签名 long long,Ubuntu 14.04,大约是 9.2e+18,从 limits.h 来看,它正好是 define LLONG_MAX 9223372036854775807LLgnu.org/software/libc/manual/html_node/…; unsigned long long 更大。是的,看到你在 Windows 上,但这应该是关于有多少位适合硬件级算法。

标签: python python-3.x cython


【解决方案1】:

cythonpyx 文件编译为 C,因此它依赖于底层 C 编译器。

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

但是有事实上的实现约定。

对于 32 位和 64 位的 Windows,intlong 使用 4 个字节(32 位),long long 使用 8 个字节(64 位)。 Win32 和 Win64 之间的区别在于指针的大小(Win32 为 32 位,Win64 为 64 位)。 (参见 MSDN 中的 Data Type Ranges])。

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 library -- 高精度算术的事实标准。 Python 有一个名为 gmpy2 的包装器。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 所以我在 cdef 语句中添加了 'i' 并重新运行它。仍然得到同样的错误。也试过 cdef long long a, b, l, i
    • 尝试cdef long d ...(并在循环中)d = data[i] 或在计算中使用然后使用d(或使用&lt;&lt;long&gt;&gt;data[i])。您可以使用标志进行编译,以查看在 cmets 中使用 python 行生成的实际 c 代码——当不涉及 python 变量时,您应该看到计算是直接的 c 表达式。 (注:由于某种原因,我无法在标记中拼写正确:))
    • 完美..我已经放弃了这个答案。做到了。你是个天才。对于那些将来阅读本文的人。我声明了 cdef long a, b, l, i, d,并将对 data[i] 的每个引用更改为 d。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多