C# 浮點數與定點數詳細解析
在 C# 中,數值類型主要分為:
- 整數型(
int
,long
等) - 浮點型(
float
,double
) - 定點型(
decimal
)
浮點數和定點數在內部的表示方式不同,導致它們的 精度、范圍、性能、使用場景 都有明顯區別。本文將詳細剖析兩者的原理與對比。
1?? 浮點數(float / double)
1.1 表示方法(IEEE 754)
浮點數采用 二進制科學計數法 存儲:
值 = (-1)^符號位 × 1.尾數 × 2^(指數 - 偏移量)
- 符號位:1 位,表示正負
- 指數位:控制縮放大小
- 尾數位:存儲有效數字
類型 | 位數 | 符號位 | 指數位 | 尾數位 |
---|---|---|---|---|
float | 32 | 1 | 8 | 23 |
double | 64 | 1 | 11 | 52 |
👉 范圍極大,但精度有限。某些小數在二進制中無法精確表示。
1.2 小數的二進制表示
浮點數小數用 2 的負次方來組合:
0.101? = 2?1 + 2?3 = 0.5 + 0.125 = 0.625
但像 0.1 這樣的十進制分數,在二進制中是無限循環小數:
0.1?? = 0.0001100110011...?
只能近似存儲 → 運算會出現誤差。
1.3 常見誤差示例
Console.WriteLine(0.1 + 0.2 == 0.3); // False
Console.WriteLine(0.1 + 0.2); // 0.30000000000000004
原因:二進制截斷 → 加法結果不是精確的 0.3。
1.4 特殊值
浮點數里其實還藏著幾個特別的數,它們在實際開發里經常會遇到:
-
正無窮 / 負無窮
當結果太大,已經超過浮點數能表示的范圍時,就會變成無窮大:double.PositiveInfinity
→ 正無窮double.NegativeInfinity
→ 負無窮
-
NaN(Not a Number,意思是“不是一個數”)
一些數學上不合法的運算會得到 NaN,比如:0.0 / 0.0
Math.Sqrt(-1)
特別注意:NaN
和任何值比較(甚至跟自己比)都會是false
。
Console.WriteLine(double.NaN == double.NaN); // false
-
+0 和 -0
浮點數里其實區分正零和負零,不過在大多數運算里,它們沒區別:-
+0 == -0
結果是true
-
但在某些場景(比如除法)下會有區別:
Console.WriteLine(1.0 / +0); // Infinity Console.WriteLine(1.0 / -0); // -Infinity
-
1.5 浮點數比較正確姿勢
- 近似比較(epsilon 容差)
bool IsEqual(double a, double b, double eps = 1e-10)=> Math.Abs(a - b) < eps;
- 游戲開發常見做法(Godot / Unity)
Mathf.Approximately(a, b); // Unity
Mathf.IsEqualApprox(a, b); // Godot
- 避免直接用
==
除非數據本身是整數運算得來的,或者特別確定是完全相等。
2?? 定點數(decimal)
2.1 表示方法
-
總共 128 位存儲:
- 96 位存有效數字
- 16 位存小數位精度(scale,小數點位置)
-
十進制方式存儲 → 可以精確表示
0.1
、0.2
、0.3
。
2.2 特點
- 高精度(28-29 位有效數字)
- 范圍比
double
小,但能避免浮點誤差 - 計算速度比浮點數慢(大約 5~20 倍),因為是軟件實現而不是硬件指令
2.3 示例
decimal a = 0.1m + 0.2m;
decimal b = 0.3m;
Console.WriteLine(a == b); // True
👉 在貨幣、金融計算中,應優先使用 decimal
。
3?? 性能對比
特性 | float/double(浮點數) | decimal(定點數) |
---|---|---|
存儲方式 | 二進制科學計數法 | 十進制定點數 |
精度 | 有誤差(約 15~16 位) | 高精度(28~29 位) |
范圍 | 極大 | 較小 |
運算速度 | 硬件支持,速度極快 | 慢(軟件實現) |
適用場景 | 科學計算、物理模擬 | 金融、貨幣 |
4?? 小結
- 浮點數 → 范圍大、速度快,但存在精度誤差
- decimal → 精度高,適合金融,但性能較差
- 判斷浮點數相等時,應使用 近似比較 而不是
==
- 在游戲或物理模擬 → 用
float/double
- 在賬務、價格計算 → 用
decimal