20.1 개요

complex 클래스는 템플릿 클래스이다. 복소수와 복소수 연산들이 필요할 때 사용하면 된다. complex 클래스는 C++을 다루는 책들에서 클래스를 정의하는 방법을 설명할 때 자주 쓰이는 예제라서, C++을 공부하셨던 분들이라면 한번쯤 정의해봤을 클래스일 것이다. C++ 표준에 포함된 complex 클래스는 템플릿으로 정의되어 있고, 복소수에 정의되어 있는 연산들이 C++에서 제공하는 수치 관련 타입들(int, float, double, long double, ...)과 사용하는데 아무런 제약이 없도록 만들어져 있다.

20.1.1 Include 화일

복소수를 사용하는 프로그램은 complex 헤더화일을 포함시켜야 한다.

   #include <complex>

 

20.2 복소수의 생성과 그 사용법

여기서는 복소수를 생성하는 방법과 복소수들간의 연산에 관해 설명하기로 한다.

20.2.1 복소수의 선언, 극형식, 보수 구하기

complex 타입의 객체를 선언하기 위해서는 먼저 복소수의 실수부와 허수부의 타입을 무엇으로 할지를 결정해야 한다. 복소수의 실수부와 허수부의 타입은 템플릿 인자로 넘겨주며, 이때, 인자의 타입은 C++에서 제공하는 부동소수 데이터 타입만이 허용된다. 즉, float, double, long double 세가지만 가능하다는 것이다.

complex 클래스는 네가지 형태의 생성자를 가지고 있다. 1)인자가 주어지지 않으면, 실수부와 허수부가 모두 0인 복소수를 생성하고, 2)인자가 하나만 주어지면, 이는 실수부의 값으로 할당되며, 허수부는 0인 복소수를 생성한다. 3)인자가 두개인 경우에는 실수부가 첫번째 인자의 값을 허수부가 두번째 인자의 값을 가지는 복소수를 생성한다. 4)마지막은 복사 생성자로서, 다른 복소수를 인자로 받아 실수부와 허수부가 동일한 복소수를 생성해낸다.

   complex<double> com1;               // 0 + 0i
   complex<double> com2(3.14);         // 3.14 + 0i
   complex<double> com3(1.5, 3.14);    // 1.5 + 3.14i
   complex<double> com4(com2);         // 3.14 + 0i (com2와 동일)

당연한 말이지만, 복소수간에는 서로 대입이 가능하다. 그리고, 복소수 타입의 변수에 실수값을 대입할 수 있는데, 이 때 실수부는 우변의 값을 가지게 되고, 허수부는 0 값을 가지게 된다. 복소수 변수에 실수값을 대입할 때는 실수를 복소수로 바꿔주는 변환 생성자(conversion constructor)가 필요하게 되는데, 이 때 앞에서 설명한 인자가 하나인 생성자를 사용한다.

   com1 = com3;                        // com1: 1.5 + 3.14i
   com3 = 2.17;                        // com3: 2.17 + 0i

polar() 함수는 극형식(크기와 위상각으로 표현)에 해당하는 복소수값을 알아내는데 사용한다.

   com4 = polar(5.6, 1.8);             // 5.6 * ( cos(1.8) + sin(1.8) i)

conj()는 인자로 주어진 복소수의 보수를 구할 때 사용한다. 주어진 복소수가 x+yi라면, 이것의 보수는 x-yi가 된다.

   complex<double> com5 = conj(com3);  // com5: 1.5 - 3.14i
함수와 멤버 함수
복소수에 관련된 연산들은 real()과 imag()를 제외하면(이들은 멤버함수), 나머지는 모두 멤버함수가 아닌 일반 함수를 통해 수행된다.

20.2.2 복소수의 실수부와 허수부

멤버함수로 제공되는 real()imag()는 각각 복소수의 실수부와 허수부를 반환한다. 이들은 멤버함수뿐만 아니라, 일반 함수의 형태로 호출할 수도 있다. 다음 두 줄은 완전히 똑같은 결과를 출력한다.

   cout << com1.real() << "+" << com1.imag() << "i" << endl;
   cout << real(com1) << "+" << imag(com1) << "i" << endl;

20.2.3 복소수의 사칙연산

+, -, *, / 연산자들은 각각 복소수의 덧셈, 뺄셈, 곱셈, 나눗셈을 수행하는데 사용한다. 이들 연산자는 두 복소수간의 사칙연산을 수행하며, 물론 복소수와 실수간의 사칙연산에도 사용할 수 있다. +=, -=, *=, /= 연산자도 정의되어 있다.

   cout << com1 + com2 << endl;
   cout << com1 - 3.14 << endl;
   cout << 2.75 * com2 << endl;
   com1 += com3 / 2.0;

단항 연산자 +-도 정의되어 있다. 단항연산자 -는 실수부와 허수부의 부호를 바꿔준다.

20.2.4 복소수의 비교

== 연산자와 != 연산자를 사용하여 복소수간의 상등관계를 알아볼 수 있다. 두 복소수의 상등관계는 실수부와 허수부가 모두 같을 때 성립한다. 단 복소수의 비교시에 반드시 유의할 점이 한가지 있는데, 이는 복소수간에는 대소 관계가 정의되어 있지 않다는 것이다. 따라서, 복소수간에는 <, >, <=, >=와 같은 비교 연산자를 적용할 수 없다.

20.2.5 스트림 입출력

복소수는 입출력 스트림을 이용한 읽기, 쓰기가 가능하다. 쉽게 말해, '<<'연산자와 '>>' 연산자를 이용하여 복소수의 출력과 입력을 수행할 수 있다는 것이다. 복소수를 출력할 때는 양쪽에 괄호를 씌워서 출력하는데, 예를 들어, 복소수 '3+4i'는 (3,4)와 같이 출력되며, '3'과 같이 허수부가 0인 복소수의 경우에는 (3)으로 출력된다.

20.2.6 복소수의 놈(norm), 절대값, 위상각 - norm(), abs(), arg()

norm() 함수는 복소수의 놈(norm)값을 반환한다. 놈(norm)이란 실수부와 허수부의 제곱의 합이다. abs() 함수는 복소수의 절대값을 반환하며, 놈(norm)의 제곱근에 해당한다. 이 두 함수는 모두 멤버함수가 아닌, 복소수를 인자로 가지는 일반 함수이다.

   cout << norm(com2) << endl;
   cout << abs(com2) << endl;

복소수의 유향 위상각은 arg()를 사용하여 얻어낼 수 있다.

   cout << com4 << " in polar coordinates is "
      << arg(com4) << " and " << norm(com4) << endl;

20.2.7 삼각함수

기존에 실수형 타입에 대해 정의되어있던 삼각함수들(sin(), cos(), tan(), sinh(), cosh(), tanh())은 복소수를 인자로 받아들일 수 있도록 확장되었다. 이들 각각은 복소수를 인자로 받아 복소수값을 반환한다.

20.2.8 초월함수

초월함수(exp(), log(), log10(), sqrt())들도 복소수를 인자로 받을 수 있게 확장되었다. 복소수를 인자로 받아 복소수를 반환한다.

표준 라이브러리에서는 여러가지 형태의 지수함수 pow()를 정의하고 있는데, 밑이 복소수이고 지수가 정수/복소수/실수인 것, 밑이 실수이고 지수가 복소수인 것들이 있다.
 

20.3 예제 프로그램 - 이차방정식의 근

이차방정식 ax2 + bx + c = 0 의 근은 다음 공식으로 구할 수 있다.

   x = (-b + sqrt(b2 - 4ac)) / 2a
     또는
   x = (-b - sqrt(b2 - 4ac)) / 2a

다음 함수는 이차방정식을 구성하는 각항의 계수를 인자로 받아 두근을 구한 뒤, 이들을 pair 객체에 담아 반환한다.

   typedef complex<double> dcomplex;

   pair<dcomplex, dcomplex> quadratic(dcomplex a, dcomplex b, dcomplex c)
   {
      dcomplex root = sqrt(b * b - 4.0 * a * c);
      a *= 2.0;
      return make_pair((-b + root) / a, (-b - root) / a);
   }