我试图用cython实现一个简单的代码,使用Jupyter笔记本(我使用python2)并使用gmp算法来处理非常大的整数。我不是gmp/cython专家。我的问题是:如何打印函数fib()中的值a。在
下面的代码返回{}。 据我所知,这和stdout有关。例如,我试过gmp_printf,但没用。在
%%cython --link-args=-lgmp
cdef extern from "gmp.h":
ctypedef struct mpz_t:
pass
cdef void mpz_init(mpz_t)
cdef void mpz_init_set_ui(mpz_t, unsigned int)
cdef void mpz_add(mpz_t, mpz_t, mpz_t)
cdef void mpz_sub(mpz_t, mpz_t, mpz_t)
cdef void mpz_add_ui(mpz_t, const mpz_t, unsigned long int)
cdef void mpz_set(mpz_t, mpz_t)
cdef void mpz_clear(mpz_t)
cdef unsigned long int mpz_get_ui(mpz_t)
cdef void mpz_set_ui(mpz_t, unsigned long int)
cdef int gmp_printf (const char*, ...)
cdef size_t mpz_out_str (FILE , int , const mpz_t)
def fib(unsigned long int n):
cdef mpz_t a,b
mpz_init(a)
mpz_init(b)
mpz_init_set_ui(a,1)
mpz_init_set_ui(b,1)
cdef int i
for i in range(n):
mpz_add(a,a,b)
mpz_sub(b,a,b)
return a
结果呢
^{pr2}$如果我使用return mpz_get_ui(a)
而不是return a
代码运行良好,但这不是我真正想要的(得到一个长整数)。在
编辑。 我在cython中将前面的代码与另一个代码进行了比较,但没有使用mpz。在
%%cython
def pyfib(unsigned long int n):
a,b=1,1
for i in range(n):
a=a+b
b=a-b
return a
最后是相同的代码,但是使用了gmpy2中的mpz
%%cython
import gmpy2
from gmpy2 import mpz
def pyfib_with_gmpy2(unsigned long int n):
cdef int i
a,b=mpz(1),mpz(1)
for i in range(n):
a=a+b
b=a-b
return a
那么
timeit fib(700000)
1 loops, best of 3: 3.19 s per loop
以及
timeit pyfib(700000)
1 loops, best of 3: 11 s per loop
以及
timeit pyfib_with_gmpy2(700000)
1 loops, best of 3: 3.28 s per loop
(答案主要是总结一堆评论)
您面临的直接问题是Python没有真正的方法来处理C结构。为了解决这个问题,Cython尝试在将结构传递给Python时将它们转换为字典(如果可能)。在这个特殊的例子中,
mpz_t
被C(以及Cython)视为“不透明”的,所以您不应该知道它的成员。因此,Cython“有帮助地”将其转换为空字典(它所知道的所有成员的正确表示)。在为了立即修复,我建议使用gmpy库,这是GMP的一个现有Python/Cython包装。这可能是一个比重复包装它的努力更好的选择。在
作为这类问题的一般解决方案,有两个明显的选择。在
您可以创建一个^{} wrapper class 。我已经链接的文档是C++,但是这个想法也可以应用到C(用{MaLoc’/‘Field’替换为{{CD3}}/del`)。这最终是一个Python类(因此可以从Cython返回到Python),但包含一个C结构,可以直接在Cython中操作它。这种方法有很好的文档记录,不需要在这里重复。
您可以在函数末尾将
mpz_t
转换回Python整数。我觉得这很有道理,因为它们最终代表的是同一件事。下面显示的代码是一个粗略的大纲,还没有经过测试(我没有安装gmp
):相关问题 更多 >
编程相关推荐