`CMPLX`, `CMPLXF`, `CMPLXL` 매크로 — 복소수 구성

CMPLX, CMPLXF, CMPLXL 매크로 — 복소수 구성

복소수를 만들 때 x + y * I처럼 쓰면 흔한데, 여기엔 미묘한 문제가 하나 있어요. I_Complex_I로 정의되어 있으면, y-0.0일 때 허수부가 +0.0으로 뒤집힐 수 있거든요. 가지 자름(branch cut)이 있는 복소 함수를 다룰 땐 이 부호가 결과를 바꿔버려요. 이 문제를 깔끔하게 피하려고 C11에서 생긴 게 CMPLX 계열 매크로예요.

출처: cppreference — CMPLX

본문

CMPLX(및 CMPLXF, CMPLXL)는 실수부와 허수부 값을 받아 지정된 복소 타입의 값으로 평가되는 표현식으로 확장되는 매크로예요. 각 값은 인자 타입으로 변환되어 실수부와 허수부가 됩니다.

float complex       CMPLXF( float real, float imag );   // (1)  (since C11)
double complex      CMPLX( double real, double imag );   // (2)  (since C11)
long double complex CMPLXL( long double real, long double imag );  // (3)  (since C11)

1-3) 각 매크로는 지정된 복소 타입의 값으로 평가되는 표현식으로 확장되며, 실수부는 real(지정 인자 타입으로 변환), 허수부는 imag(지정 인자 타입으로 변환)의 값을 가져요.

이 표현식들은, realimag 표현식도 적합하다면, static 또는 thread 저장 기간을 가진 객체의 초기화자로 쓰기에도 적합해요.

매개변수

매개변수 설명
real 반환할 복소수의 실수부
imag 반환할 복소수의 허수부

반환값

realimag를 각각 실수부·허수부로 하는 복소수를 반환해요.

Notes

이 매크로들은 허수 타입이 지원되는 것처럼 구현돼요(실제로 지원되지 않고 _Imaginary_I가 정의되어 있지 않아도요). 마치 다음과 같이 정의된 것처럼 동작해요.

#define CMPLX(x, y) ((double complex)((double)(x) + _Imaginary_I * (double)(y)))
#define CMPLXF(x, y) ((float complex)((float)(x) + _Imaginary_I * (float)(y)))
#define CMPLXL(x, y) ((long double complex)((long double)(x) + \
                      _Imaginary_I * (long double)(y)))

핵심은 _Complex_I 대신 _Imaginary_I를 사용한다는 점이에요. 허수 타입을 쓰면 음의 영 부호가 보존되기 때문에, CMPLX(0.0, -0.0) 같이 음의 영 허수부를 정확히 만들어낼 수 있어요.

예시

CMPLX로 만든 복소수의 부호를 확인해 보는 코드예요.

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = CMPLX(0.0, -0.0);
    printf("z = %.1f%+.1fi\n", creal(z), cimag(z));
}

출력:

z = 0.0-0.0i

-0.0i가 그대로 보존되어 나오는 걸 볼 수 있어요. 같은 값을 I로 만들었다면 +0.0i로 바뀌었을 테죠.

표준 참조

  • C11: 7.3.9.3 The CMPLX macros (p: 197)

더 알아보기

  • 허수 단위 상수 _Imaginary_I, _Complex_I, I가 서로 어떻게 다른지가 CMPLX를 이해하는 관건이에요.
  • 복소수를 구성하는 더 관용적인 방법인 I 매크로와 비교해 보세요.
  • cppreference의 CMPLX 원문에서 참조 절을 더 확인할 수 있어요.