次の演算子は、数値型のオペランドを使用して算術演算を実行します。
- 単項演算子:
++(インクリメント)、--(デクリメント)、+(プラス)、-(マイナス)。 - 2 項演算子:
*(乗算)、/(除算)、%(剰余)、+(加算)、-(減算)。
整数型と浮動小数点型はすべて、これらの演算子をサポートします。
int、uint、long、およびulongの型は、これらすべての演算子を定義します。 その他の整数型 (sbyte、 byte、 short、 ushort、および char) では、 ++ 演算子と -- 演算子のみが定義されます。 他の演算子では、オペランドとして整数型 sbyte、 byte、 short、 ushort、または char を使用する場合、値は int 型に変換され、結果の型は int。 オペランドが異なる整数型または浮動小数点型の場合、そのような型が存在する場合、それらの値は最も近い包含型に変換されます。 詳しくは、「C# 言語仕様」の「数値の上位変換」セクションをご覧ください。
++ 演算子と -- 演算子は、すべての整数数値型と浮動小数点数値型、および char 型に対して定義されます。
複合代入式の結果型は左側のオペランドの型です。
C# 言語リファレンスには、C# 言語の最新リリース バージョンが記載されています。 また、今後の言語リリースのパブリック プレビューの機能に関する初期ドキュメントも含まれています。
このドキュメントでは、言語の最後の 3 つのバージョンまたは現在のパブリック プレビューで最初に導入された機能を特定します。
ヒント
C# で機能が初めて導入された時期を確認するには、 C# 言語バージョン履歴に関する記事を参照してください。
インクリメント演算子 ++
単項インクリメント演算子 ++ は、オペランドを 1 ずつインクリメントします。 このオペランドは、変数、プロパティのアクセス、またはインデクサーのアクセスである必要があります。
インクリメント演算子は、後置インクリメント演算子である x++ と、前置インクリメント演算子である++x という 2 つの形式でサポートされます。
後置インクリメント演算子
次の例に示すように、x++ の結果は、演算子の "x" 値です。
int i = 3;
Console.WriteLine(i); // output: 3
Console.WriteLine(i++); // output: 3
Console.WriteLine(i); // output: 4
前置インクリメント演算子
次の例に示すように、++x の結果は、演算子の "x" 値です。
double a = 1.5;
Console.WriteLine(a); // output: 1.5
Console.WriteLine(++a); // output: 2.5
Console.WriteLine(a); // output: 2.5
デクリメント演算子 --
単項デクリメント演算子 -- は、オペランドを 1 ずつデクリメントします。 このオペランドは、変数、プロパティのアクセス、またはインデクサーのアクセスである必要があります。
デクリメント演算子は、後置デクリメント演算子、 x--、プレフィックスデクリメント演算子の 2 つの形式で使用 --x。
後置デクリメント演算子
次の例に示すように、x-- の結果は、演算子の "x" 値です。
int i = 3;
Console.WriteLine(i); // output: 3
Console.WriteLine(i--); // output: 3
Console.WriteLine(i); // output: 2
前置デクリメント演算子
次の例に示すように、--x の結果は、演算子の "x" 値です。
double a = 1.5;
Console.WriteLine(a); // output: 1.5
Console.WriteLine(--a); // output: 0.5
Console.WriteLine(a); // output: 0.5
単項プラス演算子と単項マイナス演算子
単項 + 演算子によって、そのオペランドの値が返されます。 単項 - 演算子は、そのオペランドの数値の否定を計算します。
Console.WriteLine(+4); // output: 4
Console.WriteLine(-4); // output: -4
Console.WriteLine(-(-4)); // output: 4
uint a = 5;
var b = -a;
Console.WriteLine(b); // output: -5
Console.WriteLine(b.GetType()); // output: System.Int64
Console.WriteLine(-double.NaN); // output: NaN
ulong 型は、単項 - 演算子をサポートしません。
乗算演算子 *
乗算演算子 (*) は、そのオペランドの積を計算します。
Console.WriteLine(5 * 2); // output: 10
Console.WriteLine(0.5 * 2.5); // output: 1.25
Console.WriteLine(0.1m * 23.4m); // output: 2.34
単項 * 演算子は、ポインター間接参照演算子です。
除算演算子 /
除算演算子 / は、左側のオペランドを右側のオペランドで除算します。
整数の除算
整数型のオペランドの場合、 / 演算子の結果は整数型であり、0 に丸められた 2 つのオペランドの商と等しくなります。
Console.WriteLine(13 / 5); // output: 2
Console.WriteLine(-13 / 5); // output: -2
Console.WriteLine(13 / -5); // output: -2
Console.WriteLine(-13 / -5); // output: 2
2 つのオペランドの商を浮動小数点数として取得するには、 float、 double、または decimal 型を使用します。
Console.WriteLine(13 / 5.0); // output: 2.6
int a = 13;
int b = 5;
Console.WriteLine((double)a / b); // output: 2.6
浮動小数点の除算
float、double、およびdecimal型の場合、/演算子は 2 つのオペランドの商を返します。
Console.WriteLine(16.8f / 4.1f); // output: 4.097561
Console.WriteLine(16.8d / 4.1d); // output: 4.09756097560976
Console.WriteLine(16.8m / 4.1m); // output: 4.0975609756097560975609756098
一方のオペランドがdecimal場合、floatもdoubleもdecimalへの暗黙的な変換がないため、もう一方のオペランドをfloatまたはdoubleすることはできません。
float または double オペランドは明示的に decimal 型に変換する必要があります。 数値型間の変換について詳しくは、組み込みの数値変換に関するページをご覧ください。
剰余演算子 %
剰余演算子 % は、左側のオペランドを右側のオペランドで除算した後の剰余を計算します。
整数の剰余
整数型のオペランドの場合、 a % b の結果は $a - \frac{a}{b} \times b$ によって生成される値です。 次の例に示すように、0 以外の剰余の符号は左側のオペランドの符号と一致します。
Console.WriteLine(5 % 4); // output: 1
Console.WriteLine(5 % -4); // output: 1
Console.WriteLine(-5 % 4); // output: -1
Console.WriteLine(-5 % -4); // output: -1
Math.DivRem メソッドを使用して、整数除算と剰余の結果の両方を計算します。
浮動小数点の剰余
float オペランドと double オペランドの場合、有限の x % y と x の y の結果は、次のような値 z となります。
-
zの符号 (0 以外の場合) は、xの符号と一致します。 -
zの絶対値は、計算 $|x| - n \times |y|$ から取得されます。ここで、nは $\frac{|x|} 以下の最大の整数です。{|y|}$. ここでは、$|x|$ と $|y|$ はそれぞれ、xとyの絶対値を表します。
注意
剰余を計算するこの方法は、整数オペランドに使用されるメソッドと似ていますが、IEEE 754 仕様とは異なります。 IEEE 754 の仕様に準拠する剰余演算が必要な場合、Math.IEEERemainder メソッドを使用してください。
無限オペランドがある % 演算子の動作については、C# 言語仕様に関するページの「剰余演算」セクションを参照してください。
decimalオペランドの場合、࠾余演算子%は、System.Decimal型の剰余演算子と同じように動作します。
次の例は、浮動小数点オペランドを使用して剰余演算子がどのように動作するかを示しています。
Console.WriteLine(-5.2f % 2.0f); // output: -1.2
Console.WriteLine(5.9 % 3.1); // output: 2.8
Console.WriteLine(5.9m % 3.1m); // output: 2.8
加算演算子 +
加算演算子 + は、そのオペランドの合計を計算します。
Console.WriteLine(5 + 4); // output: 9
Console.WriteLine(5 + 4.3); // output: 9.3
Console.WriteLine(5.1m + 4.2m); // output: 9.3
文字列連結とデリゲートの組み合わせにも、+ 演算子を使用できます。 詳細については、「+ および += 演算子」の記事を参照してください。
減算演算子 -
減算演算子 - は、左側のオペランドから右側のオペランドを減算します。
Console.WriteLine(47 - 3); // output: 44
Console.WriteLine(5 - 4.3); // output: 0.7
Console.WriteLine(7.5m - 2.3m); // output: 5.2
-演算子を使用してデリゲートを削除することもできます。 詳細については、 - 演算子と -= 演算子を参照してください。
複合代入。
2 項演算子 op の場合、フォームの複合代入式
x op= y
に相当します。
x = x op y
ただし、 x が評価されるのは 1 回のみです。
次の例は、算術演算子を使用した複合代入の使用方法を示しています。
int a = 5;
a += 9;
Console.WriteLine(a); // output: 14
a -= 4;
Console.WriteLine(a); // output: 10
a *= 2;
Console.WriteLine(a); // output: 20
a /= 4;
Console.WriteLine(a); // output: 5
a %= 3;
Console.WriteLine(a); // output: 2
数値の昇格のため、op操作の結果は、xの型Tに暗黙的に変換できない可能性があります。 そのような場合、op が定義済みの演算子であり、演算の結果が T の型 x に明示的に変換できる場合、x op= y の形式の複合代入式は、x = (T)(x op y) が 1 回だけ評価される点を除き、x と等価です。 次の例は、その動作を示します。
byte a = 200;
byte b = 100;
var c = a + b;
Console.WriteLine(c.GetType()); // output: System.Int32
Console.WriteLine(c); // output: 300
a += b;
Console.WriteLine(a); // output: 44
先ほどの例では、値 44 は値 300 を byte 型に変換した結果です。
注意
checked オーバーフローチェック コンテキストでは、先ほどの例は OverflowException をスローします。 詳細については、「整数の算術オーバーフロー」セクションを参照してください。
+=のサブスクリプションとサブスクリプションの解除には、-= 演算子と 演算子もそれぞれ使用できます。 詳細については、「イベントのサブスクリプションとサブスクリプション解除を行う方法」を参照してください。
演算子の優先順位と結合規則
次の一覧では、算術演算子の優先順位が最も高いものから優先順位が最も低いものの順に並べ替えられます。
- 後置インクリメント演算子
x++と後置デクリメント演算子x-- - プレフィックスインクリメント
++xとデクリメント--x演算子、および単項+演算子と-演算子 - 乗算演算子
*、/、% - 加法
+および-演算子
2 項算術演算子は左結合です。 つまり、コンパイラは、左から右に同じ優先順位レベルの演算子を評価します。
演算子の優先順位と結合規則によって定められた評価の順序を変更するには、かっこ () を使用します。
Console.WriteLine(2 + 2 * 2); // output: 6
Console.WriteLine((2 + 2) * 2); // output: 8
Console.WriteLine(9 / 5 / 2); // output: 0
Console.WriteLine(9 / (5 / 2)); // output: 4
優先度順に並べられた C# 演算子の完全な一覧については、C# 演算子に関する記事の「演算子の優先順位」セクションを参照してください。
算術オーバーフローと 0 による除算
算術演算の結果が関係する数値型の有限値の範囲外にある場合は、算術演算子の動作は、そのオペランドの型に依存します。
整数の算術オーバーフロー
0 による整数除算では、常に DivideByZeroException がスローされます。
整数の算術オーバーフローが発生した場合、オーバーフロー チェック コンテキスト (checked または unchecked) によって結果の動作が制御されます。
- checked コンテキストでは、定数式でオーバーフローが発生すると、コンパイル時エラーが発生します。 それ以外の場合は、実行時に演算が実行されると OverflowException がスローされます。
- unchecked コンテキストでは、結果の格納先の型に収まらない上位ビットが破棄されて、結果が切り詰められます。
注意
整数除算には特殊なケースがあり、オフのコンテキストでも ArithmeticException をスローできます。 左オペランドが符号付き整数型 (int.MinValue または long.MinValue) の最小値であり、右側のオペランドが -1場合、結果を変換先の型で表すことはできません。 .NET ランタイムは、次の例に示すように、この場合に ArithmeticException をスローします。
int a = int.MinValue;
int b = -1;
try
{
int c = unchecked(a / b);
}
catch (ArithmeticException)
{
Console.WriteLine($"Overflow occurred when dividing {a} by {b}.");
}
checked と unchecked のステートメントとともに、checked および unchecked 演算子を使用して、式が評価されるオーバーフロー チェック コンテキストを制御することができます。
int a = int.MaxValue;
int b = 3;
Console.WriteLine(unchecked(a + b)); // output: -2147483646
try
{
int d = checked(a + b);
}
catch(OverflowException)
{
Console.WriteLine($"Overflow occurred when adding {a} to {b}.");
}
既定では、算術演算は unchecked コンテキストで発生します。
浮動小数点演算のオーバーフロー
float型とdouble型を使用した算術演算では、例外はスローされません。 これらの型を使用した算術演算の結果は、無限大と非数値を表す特殊な値のいずれかになります。
double a = 1.0 / 0.0;
Console.WriteLine(a); // output: Infinity
Console.WriteLine(double.IsInfinity(a)); // output: True
Console.WriteLine(double.MaxValue + double.MaxValue); // output: Infinity
double b = 0.0 / 0.0;
Console.WriteLine(b); // output: NaN
Console.WriteLine(double.IsNaN(b)); // output: True
decimal 型のオペランドの場合、算術オーバーフローでは常に OverflowException がスローされます。 0 による除算では常に DivideByZeroException がスローされます。
丸め誤差
実数と浮動小数点演算の浮動小数点表現には一般的な制限があるため、浮動小数点型を使用する計算では丸めエラーが発生する可能性があります。 式の結果は、予期される数学的結果とは異なる場合があります。 次の例は、こうしたいくつかのケースを示しています。
Console.WriteLine(.41f % .2f); // output: 0.00999999
double a = 0.1;
double b = 3 * a;
Console.WriteLine(b == 0.3); // output: False
Console.WriteLine(b - 0.3); // output: 5.55111512312578E-17
decimal c = 1 / 3.0m;
decimal d = 3 * c;
Console.WriteLine(d == 1.0m); // output: False
Console.WriteLine(d); // output: 0.9999999999999999999999999999
詳細については、System.Double、System.Single、または System.Decimal のリファレンス ページの解説を参照してください。
演算子のオーバーロード可/不可
ユーザー定義型の単項 (++、--、+、-) およびバイナリ (*、/、%、+、-) 算術演算子をオーバーロードできます。 二項演算子をオーバーロードすると、対応する複合代入演算子も暗黙的にオーバーロードされます。 C# 14 以降では、ユーザー定義型は複合代入演算子 (op=) を明示的にオーバーロードして、より効率的な実装を提供できます。 通常、型は、操作の結果を格納するために新しいインスタンスを割り当てるのではなく、値をインプレースで更新できるため、これらの演算子をオーバーロードします。 型が明示的なオーバーロードを提供しない場合、コンパイラは暗黙的なオーバーロードを生成します。
ユーザー定義の checked 演算子
算術演算子をオーバーロードする場合は、 checked キーワードを使用して、その演算子の チェック されたバージョンを定義できます。 その方法を次の例に示します。
public record struct Point(int X, int Y)
{
public static Point operator checked +(Point left, Point right)
{
checked
{
return new Point(left.X + right.X, left.Y + right.Y);
}
}
public static Point operator +(Point left, Point right)
{
return new Point(left.X + right.X, left.Y + right.Y);
}
}
checked 演算子を定義するとき、checked 修飾子なしで該当演算子も定義する必要があります。
checked コンテキストは checked 演算子を呼び出し、チェックされていないコンテキストはchecked修飾子なしで演算子を呼び出します。
両方のバージョンの演算子を定義すると、操作の結果が大きすぎて結果の種類を次のように表す場合にのみ動作が異なります。
- checked 演算子から OverflowException がスローされます。
-
checked修飾子のない演算子からは、"切り捨てられた" 結果を表すインスタンスが返されます。
組み込み算術演算子の動作の違いについては、「算術オーバーフローと 0 による除算」セクションを参照してください。
checked 修飾子は、次のいずれかの演算子をオーバーロードするときにのみ使用できます。
- 単項
++、--、-演算子 - 二項
*、/、+、-演算子 - 複合代入
*=、/=、+=、および-=演算子 (C# 14 以降) - 明示的な変換演算子
注意
checked修飾子は、本体内のオーバーフロー チェック コンテキストには影響しません。 既定のコンテキストは、CheckForOverflowUnderflow コンパイラ オプションの値によって定義されます。 このセクションの冒頭にある例で示されているように、checked および unchecked ステートメントを使用し、オーバーフロー チェック コンテキストを明示的に指定します。
C# 言語仕様
詳細については、「C# 言語仕様」の次のセクションを参照してください。
- 後置インクリメント演算子と後置デクリメント演算子
- 前置インクリメント演算子と前置デクリメント演算子
- 単項プラス演算子
- 単項マイナス演算子
- 乗算演算子
- 除算演算子
- 剰余演算子
- 加算演算子
- 減算演算子
- 複合代入
- checked 演算子と unchecked 演算子
- 数値の上位変換
- ユーザー定義複合割り当て
関連項目
.NET