最終更新日時: 2024年08月02日 15時00分52秒 (JST)
Akira Takahashi が更新

履歴 編集

class template
<complex>

# std::complex

    namespace std {
      template <class T>
      class complex;
    }

`<complex>`ヘッダでは、複素数を扱うクラスおよび関数を定義する。

`complex`クラステンプレートは、複素数を表すクラスである。このクラスは、実部(real part)と虚部(imaginary part)を、それぞれ型`T`の値として保持し、演算に使用する。

`complex`クラステンプレートはCV修飾されていない浮動小数点数型 (C++23以降は拡張浮動小数点数型を含む) で特殊化され、特化した実装が行われる：

これ以外の型がテンプレート引数として与えられた場合、その動作は未規定である。

### 配列へのキャスト(C++11)

`complex`クラスの左辺値オブジェクト`c`は、`reinterpret_cast<cv修飾 T(&)[2]>(c)`もしくは`reinterpret_cast<cv修飾 T*>(&c)`で浮動小数点数型の配列にキャスト可能である。その場合、配列の`0`番目は実部を表し、`1`番目は虚部を表す。

## メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ |
`~complex() = default;` | デストラクタ |
`real` | 複素数値の実部を取得／設定する |
`imag` | 複素数値の虚部を取得／設定する |
`operator=` | 複素数値のコピー |
`operator+=` | 複素数値の加算 |
`operator-=` | 複素数値の減算 |
`operator*=` | 複素数値の乗算 |
`operator/=` | 複素数値の除算 |

## メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`value_type` | 実部と虚部およびそれらの演算に使用する浮動小数点数型。テンプレートパラメータの型`T`。 |

## 非メンバ関数

### 複素数の値

名前 | 説明 | 対応バージョン
--- | --- | ---
`real` | 実部を取得する |
`imag` | 虚部を取得する |
`abs` | 複素数の絶対値を得る |
`arg` | 複素数の偏角を得る |
`norm` | 複素数体のノルムを得る |
`conj` | 共役複素数を得る |
`proj` | リーマン球面への射影を得る | C++11
`polar` | 複素数を極形式で指定して作る |

### 演算子

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator+` (単項) | 単項 `+` 演算（引数をそのまま返す） |
`operator-` (単項) | 単項 `-` 演算（符号を反転した複素数値を得る） |
`operator+` | `complex` オブジェクトを加算する |
`operator-` | `complex` オブジェクトを減算する |
`operator*` | `complex` オブジェクトを乗算する |
`operator/` | `complex` オブジェクトを除算する |
`operator==` | `complex` オブジェクトを等値比較する |
`operator!=` | `complex` オブジェクトを非等値比較する |
`operator<<` | ストリームへの出力 |
`operator>>` | ストリームからの入力 |

### リテラル

名前 | 説明 | 対応バージョン
--- | --- | ---
`i` | `complex<double>`のリテラル | C++14
`if` | `complex<float>`のリテラル | C++14
`il` | `complex<long double>`のリテラル | C++14

### 数学関数の`complex`に対するオーバーロード

名前 | 説明 | 対応バージョン
--- | --- | ---
`acos` | 複素数の逆余弦を求める | C++11
`asin` | 複素数の逆正弦を求める | C++11
`atan` | 複素数の逆正接を求める | C++11
`acosh` | 複素数の双曲線逆余弦を求める | C++11
`asinh` | 複素数の双曲線逆正弦を求める | C++11
`atanh` | 複素数の双曲線逆正接を求める | C++11
`cos` | 複素数の余弦を求める |
`cosh` | 複素数の双曲線余弦を求める |
`exp` | 自然対数の底 e の累乗（複素数）を求める。 |
`log` | 複素数の自然対数を求める |
`log10` | 複素数の常用対数を求める |
`pow` | 複素数の累乗を求める |
`sin` | 複素数の正弦を求める |
`sinh` | 複素数の双曲線正弦を求める |
`sqrt` | 複素数の平方根を求める |
`tan` | 複素数の正接を求める |
`tanh` | 複素数の双曲線正接を求める |

## タプルインタフェースサポート

名前 | 説明 | 対応バージョン
--- | --- | ---
`tuple_size` | 静的な要素数取得(class template) | C++26
`tuple_element` | 静的な要素の型取得(class template) | C++26
`get` | 要素を取得する(function template) | C++26

## 例

### 基本的な使い方

    #include <iostream>
    #include <complex>

    float pi()
    {
      return 3.141593f;
    }

    int main()
    {
      // 実部1.0f、虚部2.0fの複素数オブジェクトを作る
      std::complex<float> c(1.0f, 2.0f);

      // ストリーム出力
      std::cout << "output : " << c << std::endl;

      // 各要素の取得
      float real = c.real(); // 実部
      float imag = c.imag(); // 虚部
      std::cout << "real : " << real << std::endl;
      std::cout << "imag : " << imag << std::endl;

      // 演算
      std::complex<float> a(1.0f, 2.0f);
      std::complex<float> b(2.0f, 3.0f);
      std::cout << "a + b : " << a + b << std::endl;
      std::cout << "a - b : " << a - b << std::endl;
      std::cout << "a * b : " << a * b << std::endl;
      std::cout << "a / b : " << a / b << std::endl;

      // 各複素数の値を取得する
      std::cout << "abs : " << std::abs(c) << std::endl;   // 絶対値
      std::cout << "arg : " << std::arg(c) << std::endl;   // 偏角
      std::cout << "norm : " << std::norm(c) << std::endl; // ノルム
      std::cout << "conj : " << std::conj(c) << std::endl; // 共役複素数
      std::cout << "proj : " << std::proj(c) << std::endl; // リーマン球面への射影
      std::cout << "polar : " << std::polar(1.0f, pi() / 2.0f); // 極座標(絶対値：1.0、偏角：円周率÷2.0)から複素数を作る
    }

#### 出力

    output : (1,2)
    real : 1
    imag : 2
    a + b : (3,5)
    a - b : (-1,-1)
    a * b : (-4,7)
    a / b : (0.615385,0.0769231)
    abs : 2.23607
    arg : 1.10715
    norm : 5
    conj : (1,-2)
    proj : (1,2)
    polar : (-1.62921e-07,1)

### タプルインタフェースを使用する (C++26)

    #include <print>
    #include <complex>
    #include <vector>
    #include <ranges>

    int main()
    {
      // 構造化束縛で各要素を取得する
      {
        std::complex<float> c{1.0f, 2.0f};
        auto [real, imag] = c;
        std::println("real:{} imag:{}", real, imag);
      }

      // 定数の添字を指定して各要素を取得する
      {
        std::complex<float> c{1.0f, 2.0f};
        float real = std::get<0>(c);
        float imag = std::get<1>(c);
        std::println("real:{} imag:{}", real, imag);
      }

      // complexの配列から実部のみを抽出する
      {
        std::vector<std::complex<float>> v {
          {1.0f, 2.0f},
          {3.0f, 4.0f},
          {5.0f, 6.0f}
        };

        for (float real : v | std::views::elements<0>) {
          std::println("real:{}", real);
        }
      }
    }

#### 出力

    real:1 imag:2
    real:1 imag:2
    real:1
    real:3
    real:5

## 参照

- 複素数 - Wikipedia
- 複素数の手ほどき - 日本電気技術者協会
- 複素数とは何か - EMANの物理学
- LWG Issue 387. `std::complex` over-encapsulated
  - C++11で、`std::complex`型のメモリレイアウトが規定された経緯のレポート
- N1568 Proposed additions to TR-1 to improve compatibility with C99
- P1467R9 Extended floating-point types and standard names
  - C++23で拡張浮動小数点数型に対応した
- P2819R2 Add tuple protocol to complex
  - C++26から`std::complex`にタプルインタフェースがサポートされた