在我的64位计算机上,long long
类型有64位。
print(sizeof(long long))
# prints 8
我需要使用128位整数,幸运的是GCC supports these。我怎样才能在Cython中使用它们?
以下不起作用。编译包含just的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
编辑:这不再是一种解决方法,这是正确的方法。另请参阅@ 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
分配给int64
,可能会发生cython不需要C代码中的强制转换,因为在该过程的那一步它实际上不区分它们。
我会在这里扔两分钱。
首先,在其他答案中提出的使用外部typedef的解决方案不仅仅是一种解决方法,这就是Cython文档说这样的事情应该完成的方式。见the relevant section。引用:“如果头文件使用typedef名称(例如word
)来引用数据类型的平台相关风格,则需要相应的ctypedef语句,但是您不需要完全匹配类型,只需使用右侧的内容一般类型(int,float等)。例如ctypedef int word
无论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文件
# 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。
以下是使用@Giulio Ghirardo提出的黑客的示例。
文件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'