Cython中的abs(double complex) [英] abs(double complex) in Cython

查看:86
本文介绍了Cython中的abs(double complex)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何获取双重复数变量的绝对值?

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

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



我怎么称呼 c / cpp级别的> abs()



PS 我理解

  cdef extern来自 complex.h:
double abs(double complex)

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

  #if CYTHON_CCOMPLEX 
#定义__Pyx_c_abs_double(z)(:: std :: abs(z))
#endif

之类的东西,应该选择要包含的正确标头(< complex> compl例如:

如何利用这些指令?

解决方案

更有用的贡献



以下内容经过了半测试除了修复 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.CF
PyrexTypes.c_double_type,[
PyrexTypes.CFuncTypeArg( arg,PyrexTypes.c_double_complex_type,None)
],
is_strict_signature = True)),
BuiltinFunction(' abs,无,无, __ Pyx_c_abs {0}。format(PyrexTypes.c_float_complex_type.funcsuffix),
#utility_code = UtilityCode.load('Arithmetic','Complex.c',PyrexTypes.c_float_text(code_conplex_type。 )),
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。
PyrexTypes.c_longdouble_type,[
PyrexTypes.CFuncTypeArg( arg,PyrexTypes.c_longdouble_complex_type,None)
],
is_strict_signature = True)),

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



我可能会在提交给Cython github后将其提交'




原始答案:



由于Cython尝试对复杂类型使用本机布局,因此整个过程变得有些复杂。从Cython生成的代码中:

  #if CYTHON_CCOMPLEX 
#ifdef __cplusplus
typedef :: std: :complex<双重> __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 函数。



To更令人困惑的是,如果您查看生成的Cython代码(在生成的文件中搜索各种 #if CYTHON_CCOMPLEX 块),则Cython似乎定义了<$的快速版本c $ c> abs (以及其他有用的函数)用于所有这些类型,但无法智能地使用它们,而是依靠Python实现。



如果要通过C,则需要从 complex.h 告诉Cython有关出租车的信息:

  cdef extern来自 complex.h:
双人出租车(双人间)

def f ():
cdef double aaa = 1 + 2j
cdef double bbb =出租车(aaa)
return bbb

如果您正在使用C ++您需要告诉Cython有关C ++标准库 abs 的信息。不幸的是,它无法在其预定义包装中的 libcpp.complex.complex double complex 类型之间建立链接,因此您需要自己介绍一下函数:

  cdef extern from< complex>:
double abs(双复数)

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

如果 CYTHON_CCOMPLEX 我不知道该怎么办尚未定义,但我认为无论如何您都必须明确地执行此操作。


How do I get an absolute value for a double complex variable?

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

The second assignment is highlighted yellow in cython -a html output: aaa is converted to python object prior to applying abs().

How do I call abs() on c/cpp level?

PS I understand that

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

would solve it, but I see the following instructions in the generated c/cpp file:

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

and the like, which is supposed to choose the correct header to include (<complex> or "complex.h" or custom code) depending on the compilation flags.

How do I utilize those instructions?

解决方案

More useful contribution:

The following is semi-tested addition to fix "cython/compiler/Builtin.py". It should be pretty obvious where to add it:

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)),

It appears to work. It hasn't been run through the full Cython test-suite. It doesn't yet generate the correct code at the top of your file(but probably shouldn't need to since you already use complex double which does). It doesn't yet work in a nogil block.

I'll probably submit it to Cython github once I've looked at these issues.


Original Answer:

The whole thing is made slightly more complicated since Cython attempts to use the "native" layout for the complex type. From the code generated by 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

In all cases the types should have a compatible memory layout (I think), so the worst case is that a bit of type casting should let you use any implementation's abs function.

To add to the confusion, if you look at the generated Cython code (search through the various #if CYTHON_CCOMPLEX blocks in the generated file) it appears that Cython defines fast versions of abs (and other useful functions) for all these types, but fails to use them intelligently, falling back to the Python implementation.

If you're going through C you need to tell Cython about cabs from complex.h:

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

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

If you're going through C++ you need to tell Cython about the C++ standard library abs. Unfortunately it's unable to make the link between the libcpp.complex.complex in its predefined wrapper and the double complex type, so you need to tell it about the function yourself:

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

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

I don't immediately know what to do if CYTHON_CCOMPLEX isn't defined, but I think that's something you'd have to do explicitly anyway.

这篇关于Cython中的abs(double complex)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆