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
ヘッダのcproj
、cprojf
、cprojl
の 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()));
}
print_proj(std::complex<double>(std::numeric_limits<double>::quiet_NaN(), -std::numeric_limits<double>::infinity()));
#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()));
出力例
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 |
指定した絶対値と偏角の複素数値を得る。 |
参照
- LWG Issue 781.
std::complex
should add missing C99 functions - P1467R9 Extended floating-point types and standard names
- C++23で拡張浮動小数点数型への対応が行われ、整数型も考慮されるようになった
- P1383R2 More constexpr for
<cmath>
and<complex>
- C++26で
constexpr
対応した
- C++26で