算術運算子 (C# 參考)
下列運算子會使用數值類型的運算元來執行算術運算:
在整數類型的情況下,這些運算子 (++
和 --
運算子除外) 是針對 int
、uint
、long
和 ulong
類型所定義。 運算元是其他整數類型 (sbyte
、byte
、short
、ushort
或 char
) 時,其值會轉換成 int
類型,而這也是作業的結果類型。 運算元屬於不同的整數或浮點類型時,如果這類類型存在,則其值會轉換成最接近的包含類型。 如需詳細資訊,請參閱 C# 語言規格的數值升階一節。 ++
和 --
運算子是針對所有整數和浮點數值類型以及 char 類型所定義。 複合指派運算式的結果類型是左側運算元的類型。
遞增運算子 ++
一元遞增運算子 ++
的運算元遞增量為 1。 運算元必須是變數、屬性存取或索引子存取。
遞增運算子支援兩種形式:後置遞增運算子 x++
和前置遞增運算子 ++x
。
後置遞增運算子
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
。
後置遞減運算子
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
一元 *
運算子是一個指標間接運算子。
除法運算子 /
除法運算子 /
會將它的左邊運算元除以右邊運算元。
整數除數
針對整數型別的運算元,/
運算子的結果會是整數型別,且等於兩個運算元捨入為零的商:
Console.WriteLine(13 / 5); // output: 2
Console.WriteLine(-13 / 5); // output: -2
Console.WriteLine(13 / -5); // output: -2
Console.WriteLine(-13 / -5); // output: 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
型別,/
運算子的結果會是兩個運算元的商:
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
,因為 float
或 double
都無法隱含轉換為 decimal
。 您必須明確地將 float
或 double
運算元轉換為 decimal
型別。 如需在數值類型之間進行轉換的詳細資訊,請參閱內建數值轉換。
餘數運算子 %
餘數運算子 %
會計算其左邊運算元除以右邊運算元之後的餘數。
整數餘數
對整數型別的運算元來說,a % b
的結果是 a - (a / b) * b
所產生的值。 非零餘數的正負號與左側運算元的正負號相同,如下列範例所示:
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
不是零,其正負號與x
的正負號相同。 z
的絕對值是由|x| - n * |y|
產生的值,其中n
為最大可能整數,小於或等於|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
您也可以使用 -
運算子來進行委派移除。 如需詳細資訊,請參閱 -
和 -=
運算子一文。
複合指派
若是二元運算子 op
,表單的複合指派運算式
x op= y
相當於
x = x op y
但只會評估 x
一次。
下列範例示範如何搭配算術運算子使用複合指派:
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 = (T)(x op y)
,唯一的不同在於 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
型別的結果。
注意
在已檢查的溢位檢查內容中,上述範例會擲回 OverflowException。 如需詳細資訊,請參閱整數算術溢位一節。
您也可以使用 +=
和 -=
運算子,來分別訂閱和取消訂閱事件。 如需詳細資訊,請參閱如何訂閱及取消訂閱事件。
運算子優先順序和關聯性
下列清單會將算術運算子從最高優先順序開始排序到最低優先順序:
- 後置遞增
x++
和遞減x--
運算子 - 前置遞增
++x
和遞減--x
以及一元+
和-
運算子 - 乘法類
*
、/
和%
運算子 - 加法類
+
和-
運算子
二元算術運算子都是左向關聯。 亦即,具有相同優先順序層級的運算子會由左至右進行評估。
使用括號 ()
變更運算子優先順序和關聯性強制執行的評估順序。
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# 運算子一文的運算子優先順序一節。
算術溢位和除數為零
當算術運算的結果超出可能相關數字型別有限值的範圍之外時,算術運算子的行為取決於其運算元的型別。
整數算術溢位
整數除以零一定會擲回 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。 除數為零一律會擲回 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 參考頁面的備註。
運算子是否可多載
使用者定義型別可以多載一元 (++
、--
、+
和 -
) 和二元 (*
、/
、%
、+
與 -
) 算術運算子。 當二元運算子多載時,對應的複合指派運算子也會隱含地多載。 使用者定義類型無法明確地多載複合指派運算子。
使用者定義的 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 運算子;會在 unchecked 內容中呼叫沒有 checked
修飾元的運算子。 如果您只提供沒有 checked
修飾元的運算子,則會在 checked
和 unchecked
內容進行呼叫。
當您定義運算子的這兩個版本時,預期只有在作業結果太大而無法以結果類型表示時,其行為才會不同,如下所示:
- checked 運算子擲回 OverflowException。
- 沒有
checked
修飾元的運算子會傳回代表 truncated 結果的執行個體。
如需內建算術運算子行為差異的相關資訊,請參閱算術溢位和除數為零一節。
只有在您多載下列任何運算子時,才能使用 checked
修飾元:
- 一元
++
、--
和-
運算子 - 二元
*
、/
、+
和-
運算子 - 明確轉換運算子
注意
checked 運算子主體內的溢位檢查內容不會受到 checked
修飾元存在的影響。 預設內容是由 CheckForOverflowUnderflow 編譯器選項的值所定義。 使用 checked
和 unchecked
陳述式明確地指定溢位檢查內容,如本節開頭的範例所示範。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節:
- 後置遞增和遞減運算子
- 前置遞增和遞減運算子
- 一元加號運算子
- 一元減號運算子
- 乘法運算子
- 除法運算子
- 餘數運算子
- 加法運算子
- 減法運算子
- 複合指派
- checked 和 unchecked 運算子
- 數值升階