programing

사이톤의 복소수

batch 2023. 7. 20. 21:49
반응형

사이톤의 복소수

사이톤에서 복잡한 숫자로 작업하는 올바른 방법은 무엇입니까?

npdtype np.complex128numpy.nd의 한 C 를 작성하고 .은 Cython 서관된다같은정다니의됩이에과음연형유▁cy▁in▁in다로 됩니다.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

될 수 C할 수 는 " 지정자에 두개이며, Cyton 의해컴컴파수오 는될일수 gcc생다없니성습할유데이선지개만두에형된일지터이정의자상의언파는 "testc.663 류:25" 오류로 인해 한 것으로 .typedef npy_float64 _Complex __pyx_t_npy_float64_complex;. 이 오류는 이미 보고되었지만(: 여기) 좋은 설명 및/또는 해결책을 찾지 못했습니다.

다음을 포함하지 않음complex.h. (▁the.typedef포함되지 않음).

하지만, 여전히 문제가 있습니다. 왜냐하면 html 파일에서 생산하기 때문입니다.cython -a testcplx.pyxvarc128 = varc128 * varf64노란색이며, 이는 순수한 C로 변환되지 않았음을 의미합니다.C당드 C 코는다같습다니과해음:다▁the같니▁is습.

__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주황색(파이썬 통화)입니다.

흥미롭게도, 그 선은

vardc = vardc * vard

C로 오류로발단않순변다니 C환됩한지수하가생며으단(▁does,다니,__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및타겟이 () () 3개의 타겟이 있는 Makefile()make clean,make build,make html 무엇이든 할 수 .) 그래서 무엇이든 쉽게 테스트할 수 있습니다.

이 문제를 해결하는 가장 간단한 방법은 단순히 곱셈의 순서를 바꾸는 것입니다.

안에 있는 경우testcplx.pyx.

varc128 = varc128 * varf64

로.

varc128 = varf64 * varc128

저는 실패한 상황에서 묘사된 상황으로 올바르게 작동하는 상황으로 변경합니다.이 시나리오는 생산된 C 코드의 직접적인 차이를 허용하기 때문에 유용합니다.

tl;dr

곱셈의 순서는 번역을 변경합니다. 즉, 실패한 버전에서 곱셈은 다음을 통해 시도됩니다.__pyx_t_npy_float64_complex유형, 반면 작업 버전에서는 다음을 통해 수행됩니다.__pyx_t_double_complex define 형유가 나옵니다. 이것은 차례로 유형 정의를 도입합니다.typedef npy_float64 _Complex __pyx_t_npy_float64_complex;그것은 무효입니다.

저는 이것이 사이톤 버그라고 꽤 확신합니다(업데이트: 여기 보고됨).이것은 매우 오래된 gcc 버그 보고서이지만, 응답은 명시적으로 다음과 같이 말합니다(사실은 agcc 버그가 아니라 사용자 코드 오류임).

typedef R _Complex C;

이 코드는 유효하지 않습니다. _Complex를 typeef와 함께 사용할 수 없으며, C99에 나열된 양식 중 하나의 "float", "double" 또는 "long double"과만 함께 사용할 수 있습니다.

그들은 결론을 내립니다.double _Complex인 반면, 는 형식 지정자입니다.ArbitraryType _Complex아닙니다.이 최신 보고서의 응답 유형이 동일합니다. 사용하려고 합니다._Complex비근본적인 유형은 규격 외부에 있으며, GCC 매뉴얼은 다음을 나타냅니다._Complex만 사할수있다니습용▁be와만 할 수 .float,double그리고.long double

- C 할 수 있습니다: replace 그서 - 사톤생 C 를여해다음테킹하 : 교체다.typedef npy_float64 _Complex __pyx_t_npy_float64_complex;와 함께typedef double _Complex __pyx_t_npy_float64_complex;유효하고 출력 코드를 컴파일할 수 있는지 확인합니다.


코드를 통한 짧은 트래킹

곱셈 순서를 바꾸는 것은 컴파일러가 알려준 문제만 강조합니다.첫 번째 경우, 문제가 되는 선은 다음과 같은 것입니다.typedef npy_float64 _Complex __pyx_t_npy_float64_complex;.npy_float64 키워드를 사용합니다._Complex ▁the▁.__pyx_t_npy_float64_complex.

float _Complex또는double _Complex유형인데 , 유한유반면인형효,,반▁is▁a유▁type면.npy_float64 _Complex 그냥 삭제하시면 .npy_float64그 라인에서, 또는 그것을 대체합니다.double또는float코드는 잘 컴파일됩니다.다음 질문은 왜 그 라인이 애초에 생산되느냐는 것입니다.

이것은 사이톤 소스 코드에서 라인에 의해 생성된 것으로 보입니다.

곱셈의 요? - 이 ▁the?▁type▁that▁why까무니▁the▁such엇▁signific입이? 그렇게 해서 유형은__pyx_t_npy_float64_complex도입되고, 실패하는 방식으로 도입됩니까?

실패한 경우, 곱셈을 구현하기 위한 코드는 다음과 같습니다.varf64의 상태가.__pyx_t_npy_float64_complextype은 실제 부품과 가상 부품에 곱셈을 수행한 다음 복소수를 재조립합니다.작업 버전에서는 제품을 직접 사용합니다.__pyx_t_double_complex수를사여입력하 기능을 합니다.__Pyx_c_prod

이것은 첫 번째 변수에서 곱셈에 사용할 유형을 큐에 넣는 사이톤 코드만큼 간단하다고 생각합니다.첫 번째 경우에는 플로트 64를 보기 때문에 (잘못된) C 코드를 생성하는 반면, 두 번째 경우에는 (이중) 복합 128 유형을 보고 번역을 기반으로 합니다.이 설명은 약간 손으로 쓴 것으로 시간이 허락한다면 분석으로 돌아가기를 바랍니다...

이것에 대한 메모 - 여기서 우리는 그것을 봅니다.typedef위해서npy_float64이라double그래서 이 특별한 경우에, 수정은 사용하기 위해 여기서 코드를 수정하는 것으로 구성될 수 있습니다.double _Complextype이라npy_float64그러나 이는 SO 답변의 범위를 넘어서고 있으며 일반적인 해결책을 제시하지 못하고 있습니다.


C 코드 diff 결과

작업 버전

라인 'varc128 = varf64 * varc128에서 이 C 코드를 만듭니다.

__pyx_v_8testcplx_varc128 = __Pyx_c_prod(__pyx_t_double_complex_from_parts(__pyx_v_8testcplx_varf64, 0), __pyx_v_8testcplx_varc128);

실패한 버전

C 를 이에서를작다성니합라드 에서 만듭니다.varc128 = varc128 * varf64

__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));

이것은 추가적인 수입을 필요로 한다 - 그리고 불리한 선은 다음과 같은 것입니다.typedef npy_float64 _Complex __pyx_t_npy_float64_complex;.npy_float64 유형_Complex ▁the▁.__pyx_t_npy_float64_complex

#if CYTHON_CCOMPLEX
  #ifdef __cplusplus
    typedef ::std::complex< npy_float64 > __pyx_t_npy_float64_complex;
  #else
    typedef npy_float64 _Complex __pyx_t_npy_float64_complex;
  #endif
#else
    typedef struct { npy_float64 real, imag; } __pyx_t_npy_float64_complex;
#endif

/*... loads of other stuff the same ... */

static CYTHON_INLINE __pyx_t_npy_float64_complex __pyx_t_npy_float64_complex_from_parts(npy_float64, npy_float64);

#if CYTHON_CCOMPLEX
    #define __Pyx_c_eq_npy_float64(a, b)   ((a)==(b))
    #define __Pyx_c_sum_npy_float64(a, b)  ((a)+(b))
    #define __Pyx_c_diff_npy_float64(a, b) ((a)-(b))
    #define __Pyx_c_prod_npy_float64(a, b) ((a)*(b))
    #define __Pyx_c_quot_npy_float64(a, b) ((a)/(b))
    #define __Pyx_c_neg_npy_float64(a)     (-(a))
  #ifdef __cplusplus
    #define __Pyx_c_is_zero_npy_float64(z) ((z)==(npy_float64)0)
    #define __Pyx_c_conj_npy_float64(z)    (::std::conj(z))
    #if 1
        #define __Pyx_c_abs_npy_float64(z)     (::std::abs(z))
        #define __Pyx_c_pow_npy_float64(a, b)  (::std::pow(a, b))
    #endif
  #else
    #define __Pyx_c_is_zero_npy_float64(z) ((z)==0)
    #define __Pyx_c_conj_npy_float64(z)    (conj_npy_float64(z))
    #if 1
        #define __Pyx_c_abs_npy_float64(z)     (cabs_npy_float64(z))
        #define __Pyx_c_pow_npy_float64(a, b)  (cpow_npy_float64(a, b))
    #endif
 #endif
#else
    static CYTHON_INLINE int __Pyx_c_eq_npy_float64(__pyx_t_npy_float64_complex, __pyx_t_npy_float64_complex);
    static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_sum_npy_float64(__pyx_t_npy_float64_complex, __pyx_t_npy_float64_complex);
    static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_diff_npy_float64(__pyx_t_npy_float64_complex, __pyx_t_npy_float64_complex);
    static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_prod_npy_float64(__pyx_t_npy_float64_complex, __pyx_t_npy_float64_complex);
    static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_quot_npy_float64(__pyx_t_npy_float64_complex, __pyx_t_npy_float64_complex);
    static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_neg_npy_float64(__pyx_t_npy_float64_complex);
    static CYTHON_INLINE int __Pyx_c_is_zero_npy_float64(__pyx_t_npy_float64_complex);
    static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_conj_npy_float64(__pyx_t_npy_float64_complex);
    #if 1
        static CYTHON_INLINE npy_float64 __Pyx_c_abs_npy_float64(__pyx_t_npy_float64_complex);
        static CYTHON_INLINE __pyx_t_npy_float64_complex __Pyx_c_pow_npy_float64(__pyx_t_npy_float64_complex, __pyx_t_npy_float64_complex);
    #endif
#endif

언급URL : https://stackoverflow.com/questions/30054019/complex-numbers-in-cython

반응형