리만 구면 투영: cproj(C99)

리만 구면 투영: cproj(C99)

복소수를 무한대까지 포함해 생각하면, 모든 무한대를 하나의 점으로 모아 주는 계산이 유용할 때가 있어요. 복소평면에 무한대를 하나 추가해 구(sphere)처럼 만든 것을 **리만 구면(Riemann sphere)**이라고 불러요. 그 위로 복소수를 투영해 주는 함수가 cproj예요.

출처: cppreference

본문

시그니처

<complex.h> 헤더에 정의돼 있어요.

형태 주석
float complex cprojf ( float complex z ); (1) C99부터
double complex cproj ( double complex z ); (2) C99부터
long double complex cprojl ( long double complex z ); (3) C99부터
#define cproj(z) (4) C99부터, <tgmath.h>

동작 방식

z를 리만 구면 위에 투영한 값을 계산해요. (4)의 cproj는 타입 제네릭 매크로라서 인자 타입에 맞는 버전을 자동으로 골라 호출해 줍니다.

대부분의 z에 대해 cproj(z) == z예요. 하지만 모든 복소 무한대는 양의 실수 무한대인 INFINITY + 0.0*I 또는 INFINITY - 0.0*I가 돼요. 한 성분이 무한대이고 다른 성분이 NaN인 수조차도요. 이때 허수(영) 성분의 부호는 cimag(z)의 부호를 따라가요.

반환값

z를 리만 구면에 투영한 값을 반환해요. 모든 가능한 입력에 대해 완전히 규정된 함수라서 math_errhandling에 설명된 어떤 오류에도 걸리지 않아요.

주의할 점

cproj는 모든 무한대를 하나로(정확히는 허수 영의 부호 차이만 남기고) 모아 주면서 리만 구면을 모델링하는 데 도움을 줘요. 특히 비교 연산 같은, 다른 무한대들에서 그릇된 결과가 나올 수 있는 연산을 하기 직전에 써 주는 게 좋아요. 같은 무한대로 정규화해 두면 후속 연산이 안전해지죠.

예제

유한한 복소수와 무한대가 섞인 복소수를 각각 투영해 보는 코드예요.

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

int main(void)
{
    double complex z1 = cproj(1 + 2*I);
    printf("cproj(1+2i) = %.1f%+.1fi\n", creal(z1),cimag(z1));

    double complex z2 = cproj(INFINITY+2.0*I);
    printf("cproj(Inf+2i) = %.1f%+.1fi\n", creal(z2),cimag(z2));

    double complex z3 = cproj(INFINITY-2.0*I);
    printf("cproj(Inf-2i) = %.1f%+.1fi\n", creal(z3),cimag(z3));
}

출력:

cproj(1+2i) = 1.0+2.0i
cproj(Inf+2i) = inf+0.0i
cproj(Inf-2i) = inf-0.0i

유한한 1+2i는 그대로 남지만, 무한대가 섞인 두 입력은 모두 inf로 정규화되는 걸 볼 수 있어요. 다만 허수부의 부호만 각각 +0.0-0.0으로 유지되죠. 이 부호가 cimag(z)의 부호를 따른다는 앞선 설명과 정확히 맞는 부분이에요.

더 알아보기

  • <complex.h>의 다른 복소수 함수들.
  • cimag, creal: 허수부·실수부 추출 함수.