算術演算子
特定の算術演算の結果を返します。
演算子の名前 | 構文 | オーバーロード可能 | プロトタイプの例 (class T に対して) | |
---|---|---|---|---|
クラス定義の内側 | クラス定義の外側 | |||
正号 | +a | Yes | T T::operator+()const; | T operator+(const T &a); |
負号 | -a | Yes | T T::operator-()const; | T operator-(const T &a); |
加算 | a + b | Yes | T T::operator+(const T2 &b)const; | T operator+(const T &a, const T2 &b); |
減算 | a - b | Yes | T T::operator-(const T2 &b)const; | T operator-(const T &a, const T2 &b); |
乗算 | a * b | Yes | T T::operator*(const T2 &b)const; | T operator*(const T &a, const T2 &b); |
除算 | a / b | Yes | T T::operator/(const T2 &b)const; | T operator/(const T &a, const T2 &b); |
剰余 | a % b | Yes | T T::operator%(const T2 &b)const; | T operator%(const T &a, const T2 &b); |
ビット単位の否定 | ~a | Yes | T T::operator~()const; | T operator~(const T &a); |
ビット単位の論理積 | a & b | Yes | T T::operator&(const T2 &b)const; | T operator&(const T &a, const T2 &b); |
ビット単位の論理和 | a | b | Yes | T T::operator|(const T2 &b)const; | T operator|(const T &a, const T2 &b); |
ビット単位の排他的論理和 | a ^ b | Yes | T T::operator^(const T2 &b)const; | T operator^(const T &a, const T2 &b); |
ビット単位の左シフト | a << b | Yes | T T::operator<<(const T2 &b)const; | T operator<<(const T &a, const T2 &b); |
ビット単位の右シフト | a >> b | Yes | T T::operator>>(const T2 &b)const; | T operator>>(const T &a, const T2 &b); |
|
目次 |
[編集]説明
すべての算術演算子は特定の算術演算の結果を計算し、その結果を返します。 引数は変更されません。
[編集]変換
算術演算子に渡された被演算子が整数またはスコープなし列挙型の場合、他のいかなる動作よりも前 (しかし左辺値から右辺値への変換の後 (適用可能な場合)) に、被演算子に対して整数昇格が適用されます。 被演算子が配列または関数型の場合、配列からポインタおよび関数からポインタへの変換が適用されます。
二項演算子 (シフトを除く) について、昇格された被演算子が異なる型を持つ場合、共通の型を生成することを目標に、通常の算術変換と呼ばれる、暗黙の変換の追加のセットが適用されます (std::common_type 型特性によってもアクセス可能です)。 整数昇格の前に、一方の被演算子が列挙型であり、他方が浮動小数点型または別の列挙型であった場合、この動作は非推奨です。(C++20以上)
- いずれかの被演算子がスコープ付き列挙型の場合、変換は行われません。 他方の被演算子および戻り値の型は同じ型でなければなりません。
- そうでなく、いずれかの被演算子が longdouble の場合、他方の被演算子は longdouble に変換されます。
- そうでなく、いずれかの被演算子が double の場合、他方の被演算子は double に変換されます。
- そうでなく、いずれかの被演算子が float の場合、他方の被演算子は float に変換されます。
- そうでなければ、被演算子は整数型であり (この時点で bool, char, char8_t, char16_t, char32_t, wchar_t およびスコープなし列挙型は昇格しているため)、以下のように、共通の型を生成するために整数変換が適用されます。
- 被演算子がどちらも符号付きであるかどちらも符号なしの場合、変換順位がより低い被演算子は変換順位がより高い整数の被演算子に変換されます。
- そうでなく、符号なし被演算子の変換順位が符号付き被演算子の変換順位より大きいまたは等しい場合、符号付き被演算子は符号なし被演算子の型に変換されます。
- そうでなく、符号付き被演算子の型が符号なし被演算子のすべての値を表現できる場合、符号なし被演算子は符号付き被演算子の型に変換されます。
- そうでなければ、どちらの被演算子も、その符号付き被演算子の型に対応する符号なしの型に変換されます。
上の変換順位は、 bool, signedchar, short, int, long, longlong の順に上がります。 符号なし型の順位は対応する符号付き型の順位と同じです。 char の順位は signedchar および unsignedchar の順位と同じです。 char8_t, char16_t, char32_t および wchar_t の順位はその基になる型の順位と同じです。
[編集]オーバーフロー
符号なし整数算術は常に modulo 2n
で行われます。 ただし n はその特定の整数のビット数です。 例えば unsignedint の場合、 UINT_MAX に1を加えると 0 になり、 0 から1を引くと UINT_MAX になります。
符号付き整数算術演算がオーバーフロー (結果が結果の型に収まらない) したとき、動作は未定義です。 表現 (一般的には2の補数) のルールに従ってラップアラウンドするかもしれませんし、プラットフォームによっては、あるいはコンパイラオプション (GCC や Clang の -ftrapv
など) によってはトラップが発生するかもしれませんし、コンパイラの最適化によって完全に除去されるかもしれません。
[編集]浮動小数点環境
#pragma STDC FENV_ACCESS がサポートされていて ON
に設定されている場合、すべての浮動小数点算術は現在の浮動小数点丸め方向に従い、 math_errhandling で規定されている通りに浮動小数点算術エラーを報告します。 ただし静的初期化の一部である場合は除きます (その場合、浮動小数点例外は発生せず、丸めモードは最も近いになります)。
[編集]浮動小数点の縮約
#pragma STDC FP_CONTRACT がサポートされていて OFF
に設定されていなければ、すべての浮動小数点算術は中間結果が無限の範囲と精度を持つかのように行われる可能性があります。 つまり、丸め誤差や浮動小数点例外を省く最適化が認められます。 例えば、 C++ は (x*y)+ z を単一の融合積和 CPU 命令で実装したり、 a = x*x*x*x; を tmp = x *x; a = tmp*tmp として最適化することを認めています。
縮約とは別に、浮動小数点算術の中間結果はその型によって示されるものと異なる範囲と精度を持つことがあります。 FLT_EVAL_METHOD を参照してください。
公式には、 C++ 標準は浮動小数点演算の正確性について何の保証もしていません。
[編集]単項算術演算子
単項算術演算子は以下の形式を持ちます。
+ expression | (1) | ||||||||
- expression | (2) | ||||||||
組み込みの単項正号演算子は被演算子の値を返します。 これが無演算でない唯一の状況は、被演算子が整数昇格によって変更される整数型またはスコープなし列挙型のときです。 例えば char は int に変換されます。 あるいは被演算子が左辺値から右辺値、配列からポインタ、または関数からポインタへの変換の対象である場合です。
組み込みの単項負号演算子は昇格された被演算子の反数を計算します。 符号なしの a
の場合、 -a
の値は 2b
-a です。 ただし b
は昇格後のビット数です。
ユーザ定義の演算子に対するオーバーロード解決では、すべての昇格された算術型 A
およびすべての型 T
について、以下の関数シグネチャがオーバーロード解決に参加します。
A operator+(A) | ||
T* operator+(T*) | ||
A operator-(A) | ||
#include <iostream>int main(){char c =0x6a;int n1 =1;unsignedchar n2 =1;unsignedint n3 =1;std::cout<<"char: "<< c <<" int: "<<+c <<'\n'<<"-1, where 1 is signed: "<<-n1 <<'\n'<<"-1, where 1 is unsigned char: "<<-n2 <<'\n'<<"-1, where 1 is unsigned int: "<<-n3 <<'\n';char a[3];std::cout<<"size of array: "<< sizeof a <<'\n'<<"size of pointer: "<< sizeof +a <<'\n';}
出力:
char: j int: 106 -1, where 1 is signed: -1 -1, where 1 is unsigned char: -1 -1, where 1 is unsigned int: 4294967295 size of array: 3 size of pointer: 8
[編集]加法演算子
二項加法算術演算子式は以下の形式を持ちます。
lhs+ rhs | (1) | ||||||||
lhs- rhs | (2) | ||||||||
- どちらも算術型またはスコープなし列挙型である。 この場合、通常の算術変換は両方の被演算子に対して行われ、結果の型を決定します。
- 一方が完全に定義されたオブジェクト型へのポインタであり、他方が整数型またはスコープなし列挙型である。 この場合、結果の型はポインタの型です。
- どちらも算術型またはスコープなし列挙型である。 この場合、通常の算術変換は両方の被演算子に対して行われ、結果の型を決定します。
- lhs が完全に定義されたオブジェクト型へのポインタであり、 rhs が整数型またはスコープなし列挙型である。 この場合、結果の型はポインタの型です。
- どちらも同じ完全に定義されたオブジェクト型へのポインタである (cv 修飾は無視されます)。 この場合、結果の型は std::ptrdiff_t です。
算術型または列挙型の被演算子の場合、二項加算の結果は (通常の算術変換の後の) 被演算子の和であり、二項減算演算子の結果は (通常の算術変換の後の) 2つめの被演算子から1つめの被演算子を引いた結果です。 ただし、その型が IEEE 浮動小数点算術をサポートしている場合 (std::numeric_limits::is_iec559 を参照してください)、
- 一方の被演算子が NaN の場合、結果は NaN です。
- 無限大から無限大を引くと、 NaN になり、 FE_INVALID が発生します。
- 無限大に負の無限大を加えると、 NaN になり、 FE_INVALID が発生します。
いずれかの被演算子がポインタの場合、以下のルールが適用されます。
- 非配列オブジェクトへのポインタは、サイズ1の配列の最初の要素へのポインタとして扱われます。
- ポインタ
P
が配列のi
番目の要素を指す場合、式P+n
、n+P
およびP-n
はそれぞれ、同じ配列のi+n
番目、i+n
番目およびi-n
番目の要素を指す同じ型のポインタです。 ポインタ加算の結果は最後の次を指すポインタ (つまり、式P-1
が配列の最後の要素を指すようなポインタP
) であっても構いません。 それ以外のあらゆる状況 (同じ配列の要素または最後の次を指すのでないポインタの生成の試み) は未定義動作を発生させます。 - ポインタ
P
が配列のi
番目の要素を指し、ポインタQ
が同じ配列のj
番目の要素を指す場合、式P-Q
は、 std::ptrdiff_t に収まる場合、 i-j の値を持ちます。 両方の被演算子が同じ配列の要素 (または最後の次) を指していなければならず、そうでなければ動作は未定義です。 結果が std::ptrdiff_t に収まらない場合、動作は未定義です。 - いずれの場合も、指す先の型が配列の要素型と異なる (cv 修飾は無視します、要素自身がポインタの場合はすべての段において) 場合、ポインタ算術の動作は未定義です。 特に、派生オブジェクトの配列の要素を指す基底へのポインタを用いたポインタ算術は未定義です。
- ポインタに値 0 を加算または減算した場合、結果はそのポインタのまま変更されません。 2つのポインタが同じオブジェクトを指す、またはどちらも同じ配列の最後の次を指す、またはどちらもヌルポインタである場合、減算の結果は (std::ptrdiff_t)0 と等しくなります。
これらのポインタ算術演算子によりポインタは LegacyRandomAccessIterator の要件を満たします。
ユーザ定義の演算子に対するオーバーロード解決において、昇格した算術型 L
および R
のすべての組について、およびすべてのオブジェクト型 T
について、以下の関数シグネチャがオーバーロード解決に参加します。
LR operator+(L, R) | ||
LR operator-(L, R) | ||
T* operator+(T*, std::ptrdiff_t) | ||
T* operator+(std::ptrdiff_t, T*) | ||
T* operator-(T*, std::ptrdiff_t) | ||
std::ptrdiff_t operator-(T*, T*) | ||
ただし LR
は L
および R
に対する通常の算術変換の結果です。
#include <iostream>int main(){char c =2;unsignedint un =2;int n =-10;std::cout<<" 2 + (-10), where 2 is a char = "<< c + n <<'\n'<<" 2 + (-10), where 2 is unsigned = "<< un + n <<'\n'<<" -10 - 2.12 = "<< n -2.12<<'\n'; char a[4]={'a', 'b', 'c', 'd'};char* p =&a[1];std::cout<<"Pointer addition examples: "<<*p <<*(p +2)<<*(2+ p)<<*(p -1)<<'\n';char* p2 =&a[4];std::cout<<"Pointer difference: "<< p2 - p <<'\n';}
出力:
2 + (-10), where 2 is a char = -8 2 + (-10), where 2 is unsigned = 4294967288 -10 - 2.12 = -12.12 Pointer addition examples: bdda Pointer difference: 3
[編集]乗法演算子
二項乗法算術演算子式は以下の形式を持ちます。
lhs* rhs | (1) | ||||||||
lhs/ rhs | (2) | ||||||||
lhs% rhs | (3) | ||||||||
3つの演算子すべてについて、両方の被演算子に対して通常の算術変換が行われ、結果の型が決定されます。
二項演算子 * は (通常の算術変換の後の) 被演算子の乗算を行います。 ただし 、浮動小数点乗算の場合、
- NaN と任意の数値の乗算は NaN になります。
- 無限大とゼロの乗算は NaN になり、 FE_INVALID が発生します。
二項演算子 / は (通常の算術変換の後の) 1つめの被演算子を2つめの被演算子で割ります。
整数の被演算子の場合、これは代数的な商を生成します。
商は処理系定義の方向に丸められます。 | (C++11未満) |
商はゼロに向かって丸められます (小数部が破棄されます)。 | (C++11以上) |
2つめの被演算子がゼロの場合、動作は未定義です。 ただし浮動小数点除算が行われ、その型が IEEE 浮動小数点算術をサポートしている場合 (std::numeric_limits::is_iec559 を参照)、
- 一方の被演算子が NaN の場合、結果は NaN です。
- ゼロでない値を 0.0 で割ると、正しく符号付けされた無限大になり、 FE_DIVBYZERO が生成されます。
- 0.0 を 0.0 で割ると、 NaN になり、 FE_INVALID が生成されます。
二項演算子 % は (通常の算術変換の後の (被演算子は整数型でなければならないことに注意)) 1つめの被演算子を2つめの被演算子で整数除算した余りを生成します。 商 a/b
が結果の型で表現可能であれば、 (a/b)*b + a%b == a です。 2つめの被演算子がゼロの場合、動作は未定義です。 商 a/b
が結果の型で表現できない場合、 a/b
と a%b
の動作はどちらも未定義です (これは2の補数のシステムで INT_MIN%-1 が未定義であることを意味します)。
ノート: C++11 まで、二項演算子 % の一方または両方が負の場合、剰余の符号は処理系定義であり、整数除算の丸め方向に依存していました。 この場合、関数 std::div が well-defined な動作を提供しました。
ノート: 浮動小数点の剰余については、 std::remainder および std::fmod を参照してください。
ユーザ定義の演算子に対するオーバーロード解決において、昇格した算術型 LA
および RA
のすべての組について、および昇格した整数型 LI
および RI
のすべての組について、以下の関数シグネチャがオーバーロード解決に参加します。
LRA operator*(LA, RA) | ||
LRA operator/(LA, RA) | ||
LRI operator%(LI, RI) | ||
ただし LRx
は Lx
および Rx
に対する通常の算術変換の結果です。
#include <iostream>int main(){char c =2;unsignedint un =2;int n =-10;std::cout<<"2 * (-10), where 2 is a char = "<< c * n <<'\n'<<"2 * (-10), where 2 is unsigned = "<< un * n <<'\n'<<"-10 / 2.12 = "<< n /2.12<<'\n'<<"-10 / 21 = "<< n /21<<'\n'<<"-10 % 21 = "<< n %21<<'\n';}
出力:
2 * (-10), where 2 is a char = -20 2 * (-10), where 2 is unsigned = 4294967276 -10 / 2.12 = -4.71698 -10 / 21 = 0 -10 % 21 = -10
[編集]ビット単位の論理演算子
ビット単位の算術演算子式は以下の形式を持ちます。
~ rhs | (1) | ||||||||
lhs& rhs | (2) | ||||||||
lhs| rhs | (3) | ||||||||
lhs^ rhs | (4) | ||||||||
演算子 ~ は (昇格後の) 引数の値のビット単位の否定 (1の補数) です。 演算子 & の結果は (通常の算術変換の後の) 被演算子のビット単位の論理積の値です。 演算子 | の結果は (通常の算術変換の後の) 被演算子のビット単位の論理和の値です。 演算子 ^ の結果は (通常の算術変換の後の) 被演算子のビット単位の排他的論理和の値です。
ユーザ定義の被演算子に対するオーバーロード解決において、昇格した整数型 L
および R
のすべての組について、以下の関数シグネチャがオーバーロード解決に参加します。
R operator~(R) | ||
LR operator&(L, R) | ||
LR operator^(L, R) | ||
LR operator|(L, R) | ||
ただし LR
は L
および R
に対する通常の算術変換の結果です。
#include <iostream>int main(){std::cout<<std::hex<<std::showbase; uint16_t mask =0x00f0; uint32_t a =0x12345678;std::cout<<"Value: "<< a <<" mask: "<< mask <<'\n'<<"Setting bits: "<<(a | mask)<<'\n'<<"Clearing bits: "<<(a & ~mask)<<'\n'<<"Selecting bits: "<<(a & mask)<<'\n';}
出力:
Value: 0x12345678 mask: 0xf0 Setting bits: 0x123456f8 Clearing bits: 0x12345608 Selecting bits: 0x70
[編集]ビット単位のシフト演算子
ビット単位のシフト演算子式は以下の形式を持ちます。
lhs<< rhs | (1) | ||||||||
lhs>> rhs | (2) | ||||||||
戻り値の型は整数昇格後の左の被演算子の型です。
符号なしの
負の 符号なしの | (C++20未満) | ||||
| (C++20以上) |
いずれの場合においても、右の被演算子の値が負または昇格した左の被演算子のビット数以上の場合、動作は未定義です。
ユーザ定義の被演算子に対するオーバーロード解決において、昇格した整数型 L
および R
のすべての組について、以下の関数シグネチャがオーバーロード解決に参加します。
L operator<<(L, R) | ||
L operator>>(L, R) | ||
#include <iostream>enum{ONE=1, TWO=2};int main(){std::cout<<std::hex<<std::showbase;char c =0x10;unsignedlonglong ull =0x123;std::cout<<"0x123 << 1 = "<<(ull <<1)<<'\n'<<"0x123 << 63 = "<<(ull <<63)<<'\n'// overflow in unsigned<<"0x10 << 10 = "<<(c <<10)<<'\n';// char is promoted to intlonglong ll =-1000;std::cout<<std::dec<<"-1000 >> 1 = "<<(ll >> ONE)<<'\n';}
出力:
0x123 << 1 = 0x246 0x123 << 63 = 0x8000000000000000 0x10 << 10 = 0x4000 -1000 >> 1 = -500
[編集]標準ライブラリ
算術演算子は多くの標準ライブラリ型でオーバーロードされています。
[編集]単項算術演算子
単項 + および単項 - を実装します ( std::chrono::duration<Rep,Period> のパブリックメンバ関数) | |
複素数に単項演算子を適用します (関数テンプレート) | |
valarray の各要素に単項算術演算子を適用します ( std::valarray<T> のパブリックメンバ関数) |
[編集]加法演算子
time point に対する加算および減算を行います (関数テンプレート) | |
引数として時間を取る算術演算を実装します (関数テンプレート) | |
year_month_day に何年かまたは何ヶ月かを加算または減算します ( std::chrono::year_month_day のパブリックメンバ関数) | |
2つの文字列または文字列と文字を連結します (関数テンプレート) | |
イテレータを前進または後退させます ( std::reverse_iterator<Iter> のパブリックメンバ関数) | |
イテレータを前進または後退させます ( std::move_iterator<Iter> のパブリックメンバ関数) | |
2つの複素数または複素数とスカラーに対して複素数算術を行います (関数テンプレート) | |
2つの valarray の各要素または valarray と値に二項演算子を適用します (関数テンプレート) |
[編集]乗法演算子
引数として時間を取る算術演算を実装します (関数テンプレート) | |
2つの複素数または複素数とスカラーに対して複素数算術を行います (関数テンプレート) | |
2つの valarray の各要素または valarray と値に二項演算子を適用します (関数テンプレート) |
[編集]ビット単位の論理演算子
バイナリ論理積、論理和、排他的論理和、論理否定を行います ( std::bitset<N> のパブリックメンバ関数) | |
ビットセットに対してバイナリ論理演算を行います (関数テンプレート) | |
valarray の各要素に単項算術演算子を適用します ( std::valarray<T> のパブリックメンバ関数) | |
2つの valarray の各要素または valarray と値に二項演算子を適用します (関数テンプレート) |
[編集]ビット単位のシフト演算子
2つの valarray の各要素または valarray と値に二項演算子を適用します (関数テンプレート) | |
バイナリ左シフトおよび右シフトを行います ( std::bitset<N> のパブリックメンバ関数) |
[編集]ストリーム挿入/抽出演算子
標準ライブラリの至る所で、ビット単位のシフト演算子は、左の被演算子または戻り値の型として入出力ストリーム (std::ios_base& またはそれから派生したクラスのいずれか) を使用して、よくオーバーロードされています。 このような演算子はストリーム挿入およびストリーム抽出演算子と呼ばれます。
書式付きデータを抽出します ( std::basic_istream<CharT,Traits> のパブリックメンバ関数) | |
文字と文字配列を抽出します (関数テンプレート) | |
書式付きデータを挿入します ( std::basic_ostream<CharT,Traits> のパブリックメンバ関数) | |
文字データを挿入します (関数テンプレート) | |
複素数をシリアライズおよびデシリアライズします (関数テンプレート) | |
ビットセットのストリーム入出力を行います (関数テンプレート) | |
文字列のストリーム入出力を行います (関数テンプレート) | |
擬似乱数エンジンに対してストリーム入出力を行います (関数テンプレート) | |
乱数分布に対してストリーム入出力を行います (関数テンプレート) |
[編集]関連項目
一般的な演算子 | ||||||
---|---|---|---|---|---|---|
代入 | インクリメント デクリメント | 算術 | 論理 | 比較 | メンバアクセス | その他 |
a = b | ++a | +a | !a | a == b | a[b] | a(...) |
特殊な演算子 | ||||||
static_cast は型を別の関連する型に変換します。 |
算術演算子 の C言語リファレンス |