在我的64位计算机上,long long
类型有64位。
print(sizeof(long long))
# prints 8
我需要使用128位整数,幸运的是GCC supports these。我怎样才能在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
答案 0 :(得分:9)
编辑:这不再是一种解决方法,这是正确的方法。另请参阅@ 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代码中进行强制转换,因为在该过程的该步骤中它实际上不区分它们
答案 1 :(得分:4)
我会把我的两分钱扔到这里。
首先,在其他答案中提出的使用外部typedef的解决方案不仅仅是一种解决方法,这就是Cython docs应该这样做的事情。
见the relevant section。
Quote:“如果头文件使用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。
答案 2 :(得分:3)
以下是使用@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'