gpt4 book ai didi

cython - 如何在 'language=c++'模式下使用C复数?

转载 作者:行者123 更新时间:2023-12-04 09:46:05 27 4
gpt4 key购买 nike

我的大部分库都是在“正常”C 模式下用 Cython 编写的。到目前为止,我很少需要任何 C++ 功能,但总是假设(有时确实如此!)如果我愿意,我可以只为一个模块切换到 C++ 模式。

所以我有 10 多个 C 模式模块和 1 个 C++ 模式模块。

现在的问题是 Cython 似乎如何处理复数定义。在 C 模式下,它假设我认为是 C 复数,而在 C++ 模式下,它假设我认为是 C++ 复数。我读过它们现在甚至可能是相同的,但无论如何 Cython 提示它们不是:

openChargeState/utility/cheb.cpp:2895:35: error: cannot convert ‘__pyx_t_double_complex {aka std::complex<double>}’ to ‘__complex__ double’ for argument ‘1’ to ‘double cabs(__complex__ double)’
__pyx_t_5 = ((cabs(__pyx_v_num) == INFINITY) != 0);

在那种情况下,我尝试使用 C 模式模块中定义的出租车,并从 C++ 模式模块调用它。

我知道有一些明显的解决方法(现在我只是不使用 C++ 模式;我想使用向量,而不是现在使用较慢的 Python 列表)。

有没有办法告诉我的 C++ 模式模块使用 C 复数,或者告诉它它们是相同的?如果我在我的 C++ 模式模块中找不到 ctypedef C 复数的工作方法...或者是否有任何其他解决方案?


编辑: DavidW 和 ead 的评论提出了一些合理的建议。首先是最小工作示例。

设置.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize

extra_compile_args=['-O3']
compdir = {'language_level' : '3'}

extensions = cythonize([
Extension("cmod", ["cmod.pyx"]),
Extension("cppmod", ["cppmod.pyx"], language='c++')
],
compiler_directives = compdir
)

setup(cmdclass = {'build_ext': build_ext},
ext_modules = extensions
)

import cppmod

cmod.pyx

cdef double complex c_complex_fun(double complex xx):
return xx**2

cmod.pxd

cdef double complex c_complex_fun(double complex xx)

cdef extern from "complex.h":
double cabs(double complex zz) nogil

cppmod.pyx

cimport cmod

cdef double complex cpp_complex_fun(double complex xx):
return cmod.c_complex_fun(xx)*abs(xx) # cmod.cabs(xx) doesn't work here

print(cpp_complex_fun(5.5))

然后用 python3 setup.py build_ext --inplace 编译。

现在有趣的部分是(如代码中所写)只有“间接”导入的 c 函数有问题,在我的例子中是 cabs。所以只使用 abs 的建议实际上确实有帮助,但我仍然不理解底层逻辑。我希望我不会在另一个问题中遇到这个问题。我暂时不提这个问题。也许有人知道发生了什么。

最佳答案

您的问题与以下事实无关:一个模块编译为 C 扩展,另一个模块编译为 C++ 扩展 - 仅在 C++ 扩展中即可轻松重现该问题:

%%cython -+ 
cdef extern from "complex.h":
double cabs(double complex zz) nogil

def cpp_complex_fun(double complex xx):
return cabs(xx)

导致您的错误消息:

error: cannot convert __pyx_t_double_complex {aka
std::complex<double>}
to __complex__ double for argument 1 to double cabs(__complex__ double)

问题是复数是……好吧,复数。 Cython 的策略(可以查找 herehere )处理复数是使用 C/CPP 的可用实现,如果没有找到,则使用手写回退:

#if !defined(CYTHON_CCOMPLEX)
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
#elif defined(_Complex_I)
#define CYTHON_CCOMPLEX 1
#else
#define CYTHON_CCOMPLEX 0
#endif
#endif
....
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< double > __pyx_t_double_complex;
#else
typedef double _Complex __pyx_t_double_complex;
#endif
#else
typedef struct { double real, imag; } __pyx_t_double_complex;
#endif

如果是 C++ 扩展,Cython 的 double complex翻译成std::complex<double>因此不能用 cabs( double complex z ) 调用因为std::complex<double>不是 double complex .

所以实际上,这是你的“错”:你对 Cython 撒谎并告诉他,cabs有签名double cabs(std::complex<double> z) ,但这还不足以欺骗 c++ 编译器。

这意味着,在 c++ 模块中 std::abs(std::complex<double>)可以使用,或者只是 Cython/Python 的 abs ,即 automatically translated到正确的功能(然而,这对所有标准功能来说都是不可能的)。


在 C 扩展的情况下,因为您包含了 complex.h作为所谓的“早期包含”cdef extern from "complex.h" ,因此对于上述定义 _Complex_I被定义并且 Cython 的复合体成为 double complex 的别名因此 cabs可以使用。


对于 Cython 来说,正确的做法可能是始终默认使用回退,并且用户应该能够明确选择所需的实现(double complexstd::complex<double>)。

关于cython - 如何在 'language=c++'模式下使用C复数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62106107/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com