算術演算子 (C# リファレンス)

次の演算子は、数値型のオペランドを使用して算術演算を実行します。

これらの演算子は、整数浮動小数点のすべての数値型によってサポートされています。

整数型の場合は、これらの演算子 (++ 演算子と -- 演算子を除く) が、intuintlong、および ulong 型に対して定義されます。 オペランドが他の整数型 (sbytebyteshortushortchar) のときは、それらの値は int 型に変換され、演算の結果もその型になります。 オペランドが異なる整数型または浮動小数点型の場合、それらの値は格納されている最も近い型に変換されます (その型が存在する場合)。 詳しくは、「C# 言語仕様」の「数値の上位変換」セクションをご覧ください。 ++ 演算子と -- 演算子は、すべての整数数値型と浮動小数点数値型、および char 型に対して定義されます。 複合代入式の結果型は左側のオペランドの型です。

インクリメント演算子 ++

単項インクリメント演算子 ++ は、オペランドを 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-- と、前置デクリメント演算子である --x という 2 つの形式でサポートされます。

後置デクリメント演算子

次の例に示すように、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

単項 * 演算子は、ポインター間接参照演算子です。

除算演算子 /

除算演算子 / は、左側のオペランドを右側のオペランドで除算します。

整数の除算

整数型のオペランドに対する / 演算子の結果は、整数型で、2 つのオペランドの商を 0 方向に丸めたものと等しくなります。

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 つのオペランドの商を浮動小数点数として取得するには、floatdouble、または decimal 型を使います。

Console.WriteLine(13 / 5.0);       // output: 2.6

int a = 13;
int b = 5;
Console.WriteLine((double)a / b);  // output: 2.6

浮動小数点の除算

floatdoubledecimal 型に対する / 演算子の結果は、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

オペランドの 1 つが decimal であった場合、もう 1 つのオペランドを floatdouble にすることはできません。floatdouble は暗黙的に decimal に変換できないためです。 float または double オペランドは明示的に decimal 型に変換する必要があります。 数値型間の変換について詳しくは、組み込みの数値変換に関するページをご覧ください。

剰余演算子 %

剰余演算子 % は、左側のオペランドを右側のオペランドで除算した後の剰余を計算します。

整数の剰余

整数型のオペランドの場合、a % b の結果は a - (a / b) * 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 オペランドの場合、有限の xyx % y の結果は、次のような値 z となります。

  • z の符号は、0 以外の場合、x の符号と同じになります。
  • z の絶対値は、|x| - n * |y| で生成される値となります。n は、|x| / |y| 以下で最も大きい整数であり、|x||y| はそれぞれ、xy の絶対値です。

注意

剰余を計算するこの手法は、整数オペランドに使用される手法に類似していますが、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 が定義済みの演算子であり、演算の結果が x の型 T に明示的に変換できる場合、x op= y の形式の複合代入式は、x が 1 回だけ評価される点を除き、x = (T)(x op y) と等価です。 次の例は、その動作を示します。

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 は値 300byte 型に変換した結果です。

Note

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 コンテキストでは、結果の格納先の型に収まらない上位ビットが破棄されて、結果が切り詰められます。

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.DoubleSystem.Single、または System.Decimal の参照ページの解説を参照してください。

演算子のオーバーロード可/不可

ユーザー定義型は、単項算術演算子 (++--+-) と 2 項算術演算子 (*/%+-) をオーバーロードできます。 2 項演算子をオーバーロードすると、対応する複合代入演算子も暗黙的にオーバーロードされます。 ユーザー定義型では、複合代入演算子を明示的にオーバーロードすることはできません。

ユーザー定義の checked 演算子

C# 11 以降では、算術演算子をオーバーロードするとき、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 修飾子のない演算子は unchecked コンテキストで呼び出されます。 checked 修飾子のない演算子のみを指定した場合、checked および unchecked コンテキストの両方で呼び出されます。

演算子の両方のバージョンを定義する場合、次のように演算の結果が大きすぎて結果の型で表せないときにのみ、動作は異なるものと想定されます。

  • checked 演算子から OverflowException がスローされます。
  • checked 修飾子のない演算子からは、"切り捨てられた" 結果を表すインスタンスが返されます。

組み込み算術演算子の動作の違いについては、「算術オーバーフローと 0 による除算」セクションを参照してください。

checked 修飾子は、次のいずれかの演算子をオーバーロードするときにのみ使用できます。

注意

checked 演算子の本体内のオーバーフロー チェック コンテキストは checked 修飾子の有無に影響を受けません。 既定のコンテキストは、CheckForOverflowUnderflow コンパイラ オプションの値によって定義されます。 このセクションの冒頭にある例で示されているように、checked および unchecked ステートメントを使用し、オーバーフロー チェック コンテキストを明示的に指定します。

C# 言語仕様

詳細については、「C# 言語仕様」の次のセクションを参照してください。

関連項目