11

在我的 64 位计算机上,该long long类型具有 64 位。

print(sizeof(long long))
# prints 8

我需要使用 128 位整数,幸运的是GCC 支持这些。如何在 Cython 中使用这些?

以下不起作用。编译foo.pyx只包含

cdef __int128_t x = 0

产量

$ cython foo.pyx 

Error compiling Cython file:
------------------------------------------------------------
...

cdef __int128_t x = 0
    ^
------------------------------------------------------------

foo.pyx:2:5: '__int128_t' is not a type identifier
4

3 回答 3

10

编辑:这不再是一种解决方法,这是正确的方法。另请参阅@IanH 的回答。

现在,您遇到的问题是cython无法识别您的类型,而gcc可以。所以我们可以尝试欺骗cython

文件helloworld.pyx

cdef extern from "header_int128.h":
    # this is WRONG, as this would be a int64. it is here
    # just to let cython pass the first step, which is generating
    # the .c file.
    ctypedef unsigned long long int128

print "hello world"

cpdef int foo():
    cdef int128 foo = 4
    return 32

文件header_int128.h

typedef __int128_t int128;

文件setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules = cythonize("helloworld.pyx"))

现在,在我的机器上,当我运行时python setup.py build_ext --inplace,第一步通过,文件helloworld.c生成,然后gcc编译也通过了。

现在,如果您打开文件helloworld.c,您可以检查您的变量foo是否实际声明为int128.

使用此解决方法时要非常小心。int128特别是,如果您将 an 分配给例如, cython 可能不需要在 C 代码中进行强制转换int64,因为在该过程的该步骤中,它实际上并没有区分它们。

于 2014-12-20T19:24:35.263 回答
5

我会把我的两分钱扔在这里。

首先,其他答案中提出的使用外部 typedef 的解决方案不仅仅是一种解决方法,这就是 Cython 文档所说的应该做这样的事情的方式。请参阅相关部分。引用:“如果头文件使用 typedef 名称,例如word指代数字类型的平台相关风格,您将需要相应的 ctypedef 语句,但您不需要完全匹配类型,只需使用正确的通用名称kind (int, float, etc). 例如,ctypedef int word无论 a 的实际大小是多少,都可以正常工作word(只要头文件正确定义它)。与 Python 类型的转换(如果有的话)也将用于这种新类型。 "

此外,没有必要为您已经在其他地方包含的类型实际创建带有 typedef 的头文件。就这样做

cdef extern from *:
    ctypedef int int128 "__int128_t"

或者,如果您想让 Cython 中的名称与 C 中的名称相同,

cdef extern from *:
    ctypedef int __int128_t

这是一个测试来证明这是有效的。如果 128 位算术有效a > 1,并且 a 可以表示为 64 位整数,则第一个函数将再次打印相同的数字。如果不是,整数溢出应该导致它打印 0。第二个函数显示如果使用 64 位算术会发生什么。

赛通文件

# cython: cdivision = True

cdef extern from *:
    ctypedef int int128 "__int128_t"

def myfunc(long long a):
    cdef int128 i = a
    # set c to be the largest positive integer possible for a signed 64 bit integer
    cdef long long c = 0x7fffffffffffffff
    i *= c
    cdef long long b = i / c
    print b

def myfunc_bad(long long a):
    cdef long long i = a
    # set c to be the largest positive integer possible for a signed 64 bit integer
    cdef long long c = 0x7fffffffffffffff
    i *= c
    cdef long long b = i / c
    print b

在 Python 中,在导入两个函数后,myfunc(12321)打印正确的值,同时myfunc_bad(12321)打印 0。

于 2014-12-22T19:15:41.483 回答
3

这是使用@Giulio Ghirardo 提出的hack 的示例。

该文件cbitset.px包含:

typedef unsigned __int128 bitset;

该文件bitset.pyx包含:

from libc.stdlib cimport malloc
from libc.stdio cimport printf

cdef extern from "cbitset.h":
    ctypedef unsigned long long bitset

cdef char* bitset_tostring(bitset n):
    cdef char* bitstring = <char*>malloc(8 * sizeof(bitset) * sizeof(char) + 1)
    cdef int i = 0
    while n:
        if (n & <bitset>1):
            bitstring[i] = '1'
        else:
            bitstring[i] = '0'

        n >>= <bitset>1
        i += 1
    bitstring[i] = '\0'
    return bitstring

cdef void print_bitset(bitset n):
    printf("%s\n", bitset_tostring(n))

该文件main.pyx包含:

from bitset cimport print_bitset

cdef extern from "cbitset.h":
    ctypedef unsigned long long bitset

# x contains a number consisting of more than 64 1's
cdef bitset x = (<bitset>1 << 70) - 1

print_bitset(x)
# 1111111111111111111111111111111111111111111111111111111111111111111111

该文件setup.py包含:

from distutils.core import setup
from Cython.Build import cythonize

setup(
    name="My app that used 128 bit ints",
    ext_modules=cythonize('main.pyx')
)

使用命令编译它

python3 setup.py build_ext --inplace

并使用命令运行

python3 -c 'import main'
于 2014-12-21T20:08:57.667 回答