Cython 中的 abs(双复数)

abs(double complex) in Cython

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

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

第二个分配在 cython -a html 输出中突出显示为黄色:aaa 在应用 abs() 之前转换为 python object .

如何在 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

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

如何使用这些说明?

更有用的贡献:

以下是修复 "cython/compiler/Builtin.py" 的半测试补充。添加它的位置应该很明显:

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 尝试对复杂类型使用 "native" 布局,因此整个事情变得稍微复杂一些。来自 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 你需要从 complex.h:

告诉 Cython 关于 cabs
cdef extern from "complex.h":
    double cabs(double complex)

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

如果你正在学习 C++,你需要告诉 Cython C++ 标准库 abs。不幸的是,它无法在其预定义包装器中的 libcpp.complex.complexdouble complex 类型之间创建 link ,因此您需要自己告诉它函数:

cdef extern from "<complex>":
    double abs(double complex)

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

如果 CYTHON_CCOMPLEX 未定义,我不会立即知道该怎么做,但我认为这是您无论如何都必须明确执行的事情。