`CMPLX`, `CMPLXF`, `CMPLXL` 매크로 — 복소수 구성
CMPLX, CMPLXF, CMPLXL 매크로 — 복소수 구성
복소수를 만들 때 x + y * I처럼 쓰면 흔한데, 여기엔 미묘한 문제가 하나 있어요. I가 _Complex_I로 정의되어 있으면, y가 -0.0일 때 허수부가 +0.0으로 뒤집힐 수 있거든요. 가지 자름(branch cut)이 있는 복소 함수를 다룰 땐 이 부호가 결과를 바꿔버려요. 이 문제를 깔끔하게 피하려고 C11에서 생긴 게 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(지정 인자 타입으로 변환)의 값을 가져요.
이 표현식들은, real과 imag 표현식도 적합하다면, static 또는 thread 저장 기간을 가진 객체의 초기화자로 쓰기에도 적합해요.
매개변수
| 매개변수 | 설명 |
|---|---|
real |
반환할 복소수의 실수부 |
imag |
반환할 복소수의 허수부 |
반환값
real과 imag를 각각 실수부·허수부로 하는 복소수를 반환해요.
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 원문에서 참조 절을 더 확인할 수 있어요.