乘法運算 (*) 是數值計算的核心,但在不同類型上呈現不同的溢位、精度與效能特性。C# 對整數、浮點數、decimal 定義了精確語意,並支援使用者定義型別多載。理解這些細節,對科學計算、金融系統與高效能程式庫開發至關重要。
| 特性 | 整數 (int, long...) | 浮點數 (float, double) | decimal |
|---|---|---|---|
| 溢位行為 | 環繞 (unchecked) / 例外 (checked) | ±Infinity | 例外 (OverflowException) |
| 精度 | 精確 (範圍內) | ~15-17 位 (double) | 28-29 位有效數字 |
| 特殊值 | 無 | ±0.0, ±∞, NaN | 無 |
| 交換律 | 成立 | 成立 (NaN 除外) | 成立 |
| 結合律 | 成立 (無溢位時) | 不成立 (捨入誤差) | 不成立 (捨入誤差) |
int a = 50000, b = 50000;
int c = a * b; // 2,500,000,000 → 環繞為 -1794967296 (unchecked)
// checked 語境
checked
{
int d = a * b; // OverflowException
}
// 長整數避免溢位
long e = (long)a * b; // 2,500,000,000L (正確)
// 編譯時期常數檢查
// const int overflow = 50000 * 50000; // CS0220 編譯錯誤
// 安全乘法:檢查是否溢位 (不使用 checked)
bool SafeMultiply(int a, int b, out int result)
{
if (a == 0 || b == 0) { result = 0; return true; }
if (a > 0)
{
if (b > 0) return a <= int.MaxValue / b ? (result = a * b, true) : false;
return b >= int.MinValue / a ? (result = a * b, true) : false;
}
if (b > 0) return a >= int.MinValue / b ? (result = a * b, true) : false;
return a != 0 && b >= int.MaxValue / a ? (result = a * b, true) : false;
}
// .NET 內建 (Core 2.0+)
bool ok = int.TryMultiply(a, b, out int result); // 不拋出例外,回傳是否成功
| × | 正常 > 0 | 正常 < 0 | +0.0 | -0.0 | +∞ | -∞ | NaN |
|---|---|---|---|---|---|---|---|
| 正常 > 0 | 正常 | 負正常 | +0.0 | -0.0 | +∞ | -∞ | NaN |
| 正常 < 0 | 負正常 | 正常 | -0.0 | +0.0 | -∞ | +∞ | NaN |
| +0.0 | +0.0 | -0.0 | +0.0 | -0.0 | NaN | NaN | NaN |
| -0.0 | -0.0 | +0.0 | -0.0 | +0.0 | NaN | NaN | NaN |
| +∞ | +∞ | -∞ | NaN | NaN | +∞ | -∞ | NaN |
| -∞ | -∞ | +∞ | NaN | NaN | -∞ | +∞ | NaN |
| NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
// 0 × ∞ = NaN (不定式) 0.0 * double.PositiveInfinity // NaN // 正負零 0.0 * -5.0 // -0.0 -0.0 * -5.0 // +0.0 // NaN 傳播 double.NaN * 5.0 // NaN
decimal a = 0.1m, b = 0.2m; decimal c = a * b; // 0.02 (精確,無二進位誤差) // 科學計數法 decimal d = 1.2345678901234567890123456789m; decimal e = 9.8765432109876543210987654321m; decimal f = d * e; // 12.193263111263526919530400125 (28-29 位)
decimal max = decimal.MaxValue; // ~7.9e28
decimal two = 2.0m;
var crash = max * two; // OverflowException
// 檢查模式
decimal SafeMultiply(decimal a, decimal b)
{
if (a == 0 || b == 0) return 0;
if (decimal.Abs(a) > decimal.MaxValue / decimal.Abs(b))
throw new OverflowException("Decimal 乘法溢位");
return a * b;
}
注意:C# 列舉不支援乘法運算子。列舉僅支援:
E + U、U + E (加入基底值)E - E (差值得基底型別)、E - U (減去基底值)enum Day { Mon=1, Tue=2, Wed=3 }
Day d = Day.Mon + 2; // Day.Wed (值 3)
// Day d2 = Day.Mon * 2; // 編譯錯誤:無乘法運算子
+ (串接)+ (合併)、- (移除)public readonly struct Matrix2x2
{
public double M11, M12, M21, M22;
// 矩陣乘法
public static Matrix2x2 operator *(Matrix2x2 a, Matrix2x2 b) => new Matrix2x2
{
M11 = a.M11 * b.M11 + a.M12 * b.M21,
M12 = a.M11 * b.M12 + a.M12 * b.M22,
M21 = a.M21 * b.M11 + a.M22 * b.M21,
M22 = a.M21 * b.M12 + a.M22 * b.M22
};
// 標量乘法
public static Matrix2x2 operator *(Matrix2x2 m, double k) => new Matrix2x2
{
M11 = m.M11 * k, M12 = m.M12 * k,
M21 = m.M21 * k, M22 = m.M22 * k
};
public static Matrix2x2 operator *(double k, Matrix2x2 m) => m * k; // 交換律
}
| 類型 | 指令延遲 (週期) | 吞吐率 (週期/指令) | 向量化 |
|---|---|---|---|
| int/long | 3-5 | 0.5-1 | SIMD (AVX2/AVX-512) |
| float | 4-5 | 0.5 | SIMD (4/8-wide) |
| double | 4-5 | 0.5 | SIMD (2/4-wide) |
| decimal | ~50-200 | ~50 | 無 (軟體模擬) |
// 常數摺疊 const int c = 5 * 10; // 編譯時期計算 = 50 // 強度削減:乘以 2 的冪次 → 位移 x * 2 → x << 1 x * 4 → x << 2 x * 8 → x << 3 // 乘以常數 → 移位加減組合 (編譯器自動) x * 10 → (x << 3) + (x << 1) // 8x + 2x x * 15 → (x << 4) - x // 16x - x
// System.Numerics.Vectors / System.Runtime.Intrinsics Vectora = new Vector (arr1); Vector b = new Vector (arr2); Vector c = a * b; // 單指令 4/8 個 float 並行乘法
long 或 checked/TryMultiplydecimal — 精確捨入、無二進位誤差System.Numerics 或 TensorPrimitives精通乘法運算的類型語意、溢位邊界與硬體加速路徑,是高效能數值計算與領域建模的核心能力。