• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    function template
    <complex>

    std::proj

    namespace std {
      template <class T>
      complex<T>
        proj(const complex<T>& x); // (1) C++11
      template <class T>
      constexpr complex<T>
        proj(const complex<T>& x); // (1) C++26
    
      complex<Promoted>
        proj(Arithmetic x);        // (2) C++11
      constexpr complex<Promoted>
        proj(Arithmetic x);        // (2) C++26
    }
    

    概要

    リーマン球面への射影(備考参照)を得る。proj は projection(射影、投射)の略。

    • (1) : complex<T>に対するオーバーロード
    • (2) : 算術型に対する追加のオーバーロード

    (2)は、以下のように振る舞う:

    • 実引数の型が浮動小数点数型 T の場合、complex<T> にキャストされているかのように振る舞う
    • そうでなくて、実引数が整数型の場合、complex<double> にキャストされているかのように振る舞う (C++23)

    また、これらの追加のオーバーロードが関数テンプレートなのか否か、あるいは、引数が参照型なのか否かなどについては、規格では何も言及されていない。

    戻り値

    引数 x のリーマン球面への射影

    備考

    • 本関数は、C99 の規格にある cproj(より正確には complex.h ヘッダの cprojcprojfcprojl の 3 つ。それぞれ C++ の proj<double>proj<float>proj<long double> に相当)と等価である。
    • 本関数は、x が無限大ではない場合、x そのものを返す。ここで「無限大ではない」とは、!isinf(real(x)) && !isinf(imag(x)) である。
      x が無限大の場合、complex<T>(numeric_limits<T>::infinity(), copysign(T(), imag(x))) を返す。

    リーマン球面上の複素数値

    複素数は複素平面上に表示することで2次元平面上の1点とみなすことができる。
    二次元平面はその原点から遠ざかる方向に無限の広がりを持っており、その無限遠点は原点を中心に360°の自由度を持つ。すなわち、複素数値の無限遠点は無数に存在している。

    ここに新しく1つの無限遠点を導入し、そのほかの無限遠点をそこにまとめることを考える。この時、二次元平面はその外縁部を1点にまとめるように織り込まれる(風呂敷包みのようなイメージ)。
    その1点を例えば天頂(北極点)にとり、元の平面の原点を天底(南極点)に取って織り込まれた平面を球としてみると、元の複素平面(二次元平面)はその球面上に自然に展開される。元の複素平面からこの球面上に写された複素数値は明らかに元の複素数値と同一となるが、原点(南極点)から無限に遠ざかった無限遠点だけは異なり、必ず1点(北極点)に収束するようになる。
    この様に球面上に射影され拡張された複素平面の事をリーマン球面と呼ぶ。

    リーマン球面のこの性質を用いると、複素数にを導入することができる。すなわち、本関数を通した(リーマン球面上に射影された)複素数値はその値がであるかを統一的に扱うことができるようになる。

    #include <iostream>
    #include <complex>
    #include <limits>
    
    template <class T>
    void print_proj(const std::complex<T>& c)
    {
      std::complex<T> result = std::proj(c);
    
      std::cout << "proj( " << c << " ) = " << result << std::endl;
    }
    
    int main()
    {
      print_proj(std::complex<double>(1.0, 2.0));
      print_proj(std::complex<double>(std::numeric_limits<double>::infinity(), 0.0));
      print_proj(std::complex<double>(std::numeric_limits<double>::infinity(), -0.0));
      print_proj(std::complex<double>(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::infinity()));
      print_proj(std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -std::numeric_limits<double>::infinity()));
    }
    

    出力例

    proj( (1,2) ) = (1,2)
    proj( (inf,0) ) = (inf,0)
    proj( (inf,-0) ) = (inf,-0)
    proj( (nan,inf) ) = (inf,0)
    proj( (nan,-inf) ) = (inf,-0)
    

    無限大や NaN の出力は異なる可能性がある。
    また、numeric_limits<double>::is_iec559()true でない場合、結果が異なる可能性がある。

    バージョン

    言語

    • C++11

    処理系

    • Clang: 3.0 , 3.1 , 3.2 , 3.3 , 3.4
    • GCC: 4.3.6 , 4.4.7 , 4.5.4 , 4.6.4 , 4.7.3 , 4.8.1 , 4.8.2 , 4.9.0
    • ICC: ??
    • Visual C++: 2012 , 2013 , 2015 , 2017

    備考

    • libstdc++ では(規格通りに)C++11 以降のモードでなければ本関数は使用できないが、libc++ では C++98 モードでも使用することができる。(上記の Clang が C++11 モードになっていないのはそのため)
    • libstdc++ では、通常 glibc の対応する関数を呼び出すが、glibc 2.18 以前のバージョンには NAN の取り扱いに、更に、2.11.* 以前のバージョンには通常の値の取り扱いにもバグがある。 また、glibc を使用していない libstdc++ も 4.9.0 現在、glibc 2.11.* 以前のバージョンと同様のバグがある。

    関連項目

    名前 説明
    real 複素数の実部を得る。
    imag 複素数の虚部を得る。
    abs 複素数の絶対値を得る。
    arg 複素数の偏角を得る。
    norm 複素数体のノルムを得る。
    conj 共役複素数を得る。
    polar 指定した絶対値と偏角の複素数値を得る。

    参照