Комплексные числа в Cython
Как правильно работать с комплексными числами в Cython?
Я хотел бы написать чистый цикл C, используя numpy.ndarray dtype np.complex128. В Cython связанный тип C определен вCython/Includes/numpy/__init__.pxd
как
ctypedef double complex complex128_t
так что, похоже, это простой C-двойной комплекс.
Тем не менее, легко получить странное поведение. В частности, с этими определениями
cimport numpy as np
import numpy as np
np.import_array()
cdef extern from "complex.h":
pass
cdef:
np.complex128_t varc128 = 1j
np.float64_t varf64 = 1.
double complex vardc = 1j
double vard = 1.
линия
varc128 = varc128 * varf64
может быть скомпилирован Cython, но gcc не может скомпилировать полученный код C (ошибка «testcplx.c: 663: 25: ошибка: два или более типов данных в спецификаторах объявления» и, вероятно, из-за строкиtypedef npy_float64 _Complex __pyx_t_npy_float64_complex;
). Об этой ошибке уже сообщалось (например,Вот) но я не нашел хорошего объяснения и / или чистого решения.
Без включенияcomplex.h
, нет ошибки (я думаю, потому чтоtypedef
тогда не входит).
Тем не менее, по-прежнему существует проблема, так как в HTML-файл, созданныйcython -a testcplx.pyx
, линияvarc128 = varc128 * varf64
желтый, что означает, что он не был переведен на чистый C. Соответствующий код C:
__pyx_t_2 = __Pyx_c_prod_npy_float64(__pyx_t_npy_float64_complex_from_parts(__Pyx_CREAL(__pyx_v_8testcplx_varc128), __Pyx_CIMAG(__pyx_v_8testcplx_varc128)), __pyx_t_npy_float64_complex_from_parts(__pyx_v_8testcplx_varf64, 0));
__pyx_v_8testcplx_varc128 = __pyx_t_double_complex_from_parts(__Pyx_CREAL(__pyx_t_2), __Pyx_CIMAG(__pyx_t_2));
и__Pyx_CREAL
а также__Pyx_CIMAG
оранжевые (вызовы Python).
Интересно, что линия
vardc = vardc * vard
не выдает никакой ошибки и переводится на чистый C (просто__pyx_v_8testcplx_vardc = __Pyx_c_prod(__pyx_v_8testcplx_vardc, __pyx_t_double_complex_from_parts(__pyx_v_8testcplx_vard, 0));
), тогда как он очень и очень похож на первый.
Я могу избежать ошибки, используя промежуточные переменные (и это переводит на чистый C):
vardc = varc128
vard = varf64
varc128 = vardc * vard
или просто путем приведения (но это не переводит в чистый C):
vardc = <double complex>varc128 * <double>varf64
Так что же происходит? В чем смысл ошибки компиляции? Есть ли чистый способ избежать этого? Почему умножение np.complex128_t и np.float64_t, похоже, включает вызовы Python?
ВерсииCython версии 0.22 (самая последняя версия в Pypi, когда был задан вопрос) и GCC 4.9.2.
вместилищеЯ создал крошечный репозиторий с примером (hg clone https://bitbucket.org/paugier/test_cython_complex
) и крошечный Makefile с 3 целями (make clean
, make build
, make html
) так что легко проверить что угодно.