在Cython中的abs(双复合体)

时间:2017-03-28 10:29:28

标签: python cython complex-numbers

如何获得double complex变量的绝对值?

def f():
    cdef double complex aaa = 1 + 2j
    cdef double bbb = abs(aaa)

第二个作业在cython -a html输出中以黄色突出显示:aaa在应用abs()之前转换为python对象。

如何在c / cpp级别调用abs()

PS 我理解

cdef extern from "complex.h":
    double abs(double complex)

会解决它,但我在生成的c / cpp文件中看到以下说明:

#if CYTHON_CCOMPLEX
        #define __Pyx_c_abs_double(z)     (::std::abs(z))
#endif

等,它应该根据编译标记选择正确的标题来包含(<complex>"complex.h"或自定义代码)。

我如何使用这些说明?

1 个答案:

答案 0 :(得分:1)

更有用的贡献

以下是修复&#34; cython / compiler / Builtin.py&#34;的半测试添加。在哪里添加它应该是非常明显的:

BuiltinFunction('abs',        None,    None,   "__Pyx_c_abs{0}".format(PyrexTypes.c_double_complex_type.funcsuffix),
                #utility_code = UtilityCode.load('Arithmetic', 'Complex.c', PyrexTypes.c_double_complex_type._utility_code_context()),
                func_type = PyrexTypes.CFuncType(
                    PyrexTypes.c_double_type, [
                        PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_double_complex_type, None)
                        ],
                        is_strict_signature = True)),
BuiltinFunction('abs',        None,    None,   "__Pyx_c_abs{0}".format(PyrexTypes.c_float_complex_type.funcsuffix),
                #utility_code = UtilityCode.load('Arithmetic', 'Complex.c', PyrexTypes.c_float_complex_type._utility_code_context()),
                func_type = PyrexTypes.CFuncType(
                    PyrexTypes.c_float_type, [
                        PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_float_complex_type, None)
                        ],
                        is_strict_signature = True)),
BuiltinFunction('abs',        None,    None,   "__Pyx_c_abs{0}".format(PyrexTypes.c_longdouble_complex_type.funcsuffix),
                #utility_code = UtilityCode.load('Arithmetic', 'Complex.c', PyrexTypes.c_longdouble_complex_type._utility_code_context()),
                func_type = PyrexTypes.CFuncType(
                    PyrexTypes.c_longdouble_type, [
                        PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_longdouble_complex_type, None)
                        ],
                        is_strict_signature = True)),

似乎有效。它还没有通过完整的Cython测试套件。它还没有在您的文件顶部生成正确的代码(但可能不需要,因为您已经使用了complex double。)它还没有在nogil块中工作。

在我查看这些问题之后,我可能会将它提交给Cython github。

原始答案:

由于Cython尝试使用&#34; native&#34;所以整个事情变得稍微复杂一些。复杂类型的布局。从Cython生成的代码:

#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

在所有情况下,类型都应该具有兼容的内存布局(我认为),所以最糟糕的情况是一些类型转换应该允许你使用任何实现的abs函数。

为了增加混乱,如果你看一下生成的Cython代码(在生成的文件中搜索各种#if CYTHON_CCOMPLEX块),看来Cython定义了abs的快速版本(和其他有用的)函数)用于所有这些类型,但未能智能地使用它们,回到Python实现。

如果你要通过C,你需要告诉Cython关于来自cabs的{​​{1}}:

complex.h

如果您正在使用C ++,则需要告诉Cython有关C ++标准库cdef extern from "complex.h": double cabs(double complex) def f(): cdef double complex aaa = 1 + 2j cdef double bbb = cabs(aaa) return bbb 的信息。不幸的是,它无法在预定义包装器中的abslibcpp.complex.complex类型之间建立链接,因此您需要自己告诉它有关该功能的信息:

double complex

如果cdef extern from "<complex>": double abs(double complex) def f(): cdef complex aaa = 1 + 2j cdef double bbb = abs(aaa) return bbb 未定义,我不会立即知道该怎么做,但我认为这无论如何都必须明确做。