C 언어의 복소수 산술

C 언어의 복소수 산술 (<complex.h>)

C 코드에서 제곱근을 취하거나 2차 방정식을 풀다 보면 실수만으로는 답이 안 나오는 순간이 찾아와요. 예를 들어 x * x = -1을 만족하는 실수는 없죠. 그럴 때 수학에서는 '허수 단위' i를 도입하고, a + bi 꼴의 복소수를 만들어 문제를 해결해요. C99부터 C 언어도 이런 복소수 연산을 기본 타입으로 지원해서, <complex.h>만 포함하면 별도 라이브러리 없이 복소수 계산을 할 수 있어요.

출처: cppreference — complex number arithmetic

본문

C 언어는 C99부터 세 가지 내장 복소수 타입으로 복소수 산술을 지원해요. 바로 float _Complex, double _Complex, long double _Complex예요(_Complex에 대한 자세한 내용은 해당 키워드 문서를 참고하세요). <complex.h> 헤더를 포함하면 이 세 타입을 float complex, double complex, long double complex로도 쓸 수 있어요.

복소수 타입과 별개로, 세 가지 허수 타입(imaginary type)이 지원될 수도 있어요. 바로 float _Imaginary, double _Imaginary, long double _Imaginary죠(_Imaginary 문서 참고). <complex.h>를 포함하면 이들도 float imaginary, double imaginary, long double imaginary로 접근할 수 있어요.

일반적인 산술 연산자 +, -, *, /는 실수·복소수·허수 타입을 어떤 조합으로든 섞어 쓸 수 있어요. 타입 변환 규칙은 각 타입 문서에서 더 자세히 다루게 될 거예요.

허수 지원 여부는 어떻게 알까

__STDC_IEC_559_COMPLEX__ 매크로를 정의한 컴파일러는 허수 숫자를 지원하는 것이 권장되지만, 필수는 아니에요. POSIX에서는 허수 지원 여부를 판별하기 위해 _Imaginary_I 매크로가 정의되어 있는지 확인하라고 권장하고 있어요.

  • 구현이 __STDC_NO_COMPLEX__ 매크로 상수를 정의하면, 복소수 타입과 <complex.h> 헤더, 그리고 여기에 나열된 모든 이름은 제공되지 않아요.
  • 허수 숫자가 지원되는지는 __STDC_IEC_559_COMPLEX__가 정의되었는지로 판단해요.

제공되는 함수들

<complex.h>에는 복소수를 다루는 함수들이 다음처럼 범주별로 모여 있어요.

조작(Manipulation)
함수 설명
CMPLX/CMPLXF/CMPLXL 실수부·허수부로 복소수를 구성해요
creal/crealf/creall 복소수의 실수부를 계산해요
cimag/cimagf/cimagl 복소수의 허수부를 계산해요
cabs/cabsf/cabsl 복소수의 크기(magnitude)를 계산해요
carg/cargf/cargl 복소수의 위상각(phase angle)을 계산해요
conj/conjf/conjl 복소 켤레(complex conjugate)를 계산해요
cproj/cprojf/cprojl 리만 구면(Riemann sphere) 위로의 사영을 계산해요
지수 함수
함수 설명
cexp/cexpf/cexpl 복소수 자연상수 e 지수(exponential)를 계산해요
clog/clogf/clogl 복소수 자연로그를 계산해요
거듭제곱 함수
함수 설명
cpow/cpowf/cpowl 복소수 거듭제곱 함수를 계산해요
csqrt/csqrtf/csqrtl 복소수 제곱근을 계산해요
삼각 함수
함수 설명
csin/csinf/csinl 복소수 사인(sine)을 계산해요
ccos/ccosf/ccosl 복소수 코사인(cosine)을 계산해요
ctan/ctanf/ctanl 복소수 탄젠트(tangent)를 계산해요
casin/casinf/casinl 복소수 아크사인(arc sine)을 계산해요
cacos/cacosf/cacosl 복소수 아크코사인(arc cosine)을 계산해요
catan/catanf/catanl 복소수 아크탄젠트(arc tangent)를 계산해요
쌍곡선 함수
함수 설명
csinh/csinhf/csinhl 복소수 쌍곡선 사인을 계산해요
ccosh/ccoshf/ccoshl 복소수 쌍곡선 코사인을 계산해요
ctanh/ctanhf/ctanhl 복소수 쌍곡선 탄젠트를 계산해요
casinh/casinhf/casinhl 복소수 아크쌍곡선 사인을 계산해요
cacosh/cacoshf/cacoshl 복소수 아크쌍곡선 코사인을 계산해요
catanh/catanhf/catanhl 복소수 아크쌍곡선 탄젠트를 계산해요

Notes

<complex.h>차후 추가를 위해 예약된 함수 이름이 있어요. casin, cacos, catan, csin, ccos, ctan, casinh, cacosh, catanh, csinh, ccosh, ctanh와, 여기에 -f, -l 접미사가 붙은 변형들은 <complex.h>를 포함하는 프로그램에서 쓸 수 없어요 (이미 사용 중인 이름이라 나중에 추가를 위해 막아둔 거예요).

C 표준은 역쌍곡선 함수를 "complex arc hyperbolic sine" 등으로 부르지만, 사실 쌍곡선 함수의 역함수는 **면적 함수(area functions)**예요. 그 인자는 쌍곡선 부채꼴(hyperbolic sector)의 면적이지 호(arc)가 아니거든요. 정확히는 "complex inverse hyperbolic sine"이라 부르는 게 맞고, 일부 저자는 "complex area hyperbolic sine"이라고도 해요.

복소수·허수 숫자의 무한·유한·영 판정은 각 성분 기준으로 해요.

  • 한 성분이라도 무한대이면(다른 성분이 NaN이어도) 그 복소수·허수는 무한대예요.
  • 두 성분 모두 무한대도 아니고 NaN도 아니어야 유한해요.
  • 두 성분이 모두 양의 또는 음의 영이면 그 수는 영이에요.

MSVC는 <complex.h> 헤더를 제공하긴 하지만, 복소수를 네이티브 타입으로 구현하지 않고 구조체(_C_double_complex 등)로 구현해요. 그래서 표준 C의 복소 타입과 호환되지 않고, +, -, *, / 연산자도 지원하지 않아요.

예시

러닝 예제로는 허수 단위의 제곱과 오일러 공식을 확인해 보는 코드가 좋아요.

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

int main(void)
{
    double complex z1 = I * I;     // imaginary unit squared
    printf("I * I = %.1f%+.1fi\n", creal(z1), cimag(z1));

    double complex z2 = pow(I, 2); // imaginary unit squared
    printf("pow(I, 2) = %.1f%+.1fi\n", creal(z2), cimag(z2));

    double PI = acos(-1);
    double complex z3 = exp(I * PI); // Euler's formula
    printf("exp(I*PI) = %.1f%+.1fi\n", creal(z3), cimag(z3));

    double complex z4 = 1 + 2 * I, z5 = 1 - 2 * I; // conjugates
    printf("(1+2i)*(1-2i) = %.1f%+.1fi\n", creal(z4 * z5), cimag(z4 * z5));
}

출력:

I * I = -1.0+0.0i
pow(I, 2) = -1.0+0.0i
exp(I*PI) = -1.0+0.0i
(1+2i)*(1-2i) = 5.0+0.0i

I * I-1.0+0.0i로 나오는 걸 보면 허수 단위의 정의(i² = -1)가 그대로 코드에 녹아 있다는 게 느껴져요. 그리고 exp(I*PI)-1.0로 나오는 건 오일러 공식 e^(iπ) = -1을 그대로 확인해 주는 좋은 예시죠. (1+2i)(1-2i)는 켤레곱이라 순수한 실수 5가 나와요.

표준 참조

이 기능은 표준의 다음 절에서 정의돼요.

  • C23: 6.10.8.3 __STDC_NO_COMPLEX__, __STDC_IEC_559_COMPLEX__, 7.3 Complex arithmetic <complex.h>, 7.25 Type-generic math <tgmath.h>, 7.31.1, Annex G
  • C17: 6.10.8.3, 7.3 (p: 136-144), 7.25 (p: 272-273), 7.31.1 (p: 391), Annex G (p: 469-479)
  • C11: 6.10.8.3, 7.3 (p: 188-199), 7.25 (p: 373-375), 7.31.1 (p: 455), Annex G (p: 532-545)
  • C99: 6.10.8/2, 7.3 (p: 170-180), 7.22 (p: 335-337), 7.26.1 (p: 401), Annex G (p: 467-480)

더 알아보기

  • 복소수 타입을 선언하는 키워드 _Complex와 허수 타입 _Imaginary를 살펴보면 타입 체계를 더 깊게 이해할 수 있어요.
  • 복소수를 구성하는 CMPLX 매크로와 허수 단위 상수 I, _Complex_I, _Imaginary_I가 실제로 어떻게 동작하는지가 핵심이에요.
  • 실수 대상의 수학 함수(fabs, atan2, hypot 등)와 짝을 이루는 복소 버전을 비교해 보면 규칙이 보여요.
  • cppreference의 복소수 산술 원문에서 참조 절과 결함 기록을 더 확인할 수 있어요.