C#?浮點(diǎn)數(shù)與定點(diǎn)數(shù)的原理與用法對(duì)比
C# 浮點(diǎn)數(shù)與定點(diǎn)數(shù)詳細(xì)解析
在 C# 中,數(shù)值類(lèi)型主要分為:
- 整數(shù)型(
int,long等) - 浮點(diǎn)型(
float,double) - 定點(diǎn)型(
decimal)
浮點(diǎn)數(shù)和定點(diǎn)數(shù)在內(nèi)部的表示方式不同,導(dǎo)致它們的 精度、范圍、性能、使用場(chǎng)景 都有明顯區(qū)別。本文將詳細(xì)剖析兩者的原理與對(duì)比。
1?? 浮點(diǎn)數(shù)(float / double)
1.1 表示方法(IEEE 754)
浮點(diǎn)數(shù)采用 二進(jìn)制科學(xué)計(jì)數(shù)法 存儲(chǔ):
值 = (-1)^符號(hào)位 × 1.尾數(shù) × 2^(指數(shù) - 偏移量)
- 符號(hào)位:1 位,表示正負(fù)
- 指數(shù)位:控制縮放大小
- 尾數(shù)位:存儲(chǔ)有效數(shù)字
| 類(lèi)型 | 位數(shù) | 符號(hào)位 | 指數(shù)位 | 尾數(shù)位 |
|---|---|---|---|---|
| float | 32 | 1 | 8 | 23 |
| double | 64 | 1 | 11 | 52 |
?? 范圍極大,但精度有限。某些小數(shù)在二進(jìn)制中無(wú)法精確表示。
1.2 小數(shù)的二進(jìn)制表示
浮點(diǎn)數(shù)小數(shù)用 2 的負(fù)次方來(lái)組合:
0.101? = 2?1 + 2?3 = 0.5 + 0.125 = 0.625
但像 0.1 這樣的十進(jìn)制分?jǐn)?shù),在二進(jìn)制中是無(wú)限循環(huán)小數(shù):
0.1?? = 0.0001100110011...?
只能近似存儲(chǔ) → 運(yùn)算會(huì)出現(xiàn)誤差。
1.3 常見(jiàn)誤差示例
Console.WriteLine(0.1 + 0.2 == 0.3); // False Console.WriteLine(0.1 + 0.2); // 0.30000000000000004
原因:二進(jìn)制截?cái)?→ 加法結(jié)果不是精確的 0.3。
1.4 特殊值
浮點(diǎn)數(shù)里其實(shí)還藏著幾個(gè)特別的數(shù),它們?cè)趯?shí)際開(kāi)發(fā)里經(jīng)常會(huì)遇到:
- 正無(wú)窮 / 負(fù)無(wú)窮
- 當(dāng)結(jié)果太大,已經(jīng)超過(guò)浮點(diǎn)數(shù)能表示的范圍時(shí),就會(huì)變成無(wú)窮大:
double.PositiveInfinity→ 正無(wú)窮double.NegativeInfinity→ 負(fù)無(wú)窮- NaN(Not a Number,意思是“不是一個(gè)數(shù)”)
- 一些數(shù)學(xué)上不合法的運(yùn)算會(huì)得到 NaN,比如:
Console.WriteLine(double.NaN == double.NaN); // false
0.0 / 0.0Math.Sqrt(-1)- 特別注意:
NaN和任何值比較(甚至跟自己比)都會(huì)是false。 - +0 和 -0
- 浮點(diǎn)數(shù)里其實(shí)區(qū)分正零和負(fù)零,不過(guò)在大多數(shù)運(yùn)算里,它們沒(méi)區(qū)別:
+0 == -0結(jié)果是true- 但在某些場(chǎng)景(比如除法)下會(huì)有區(qū)別:
Console.WriteLine(1.0 / +0); // Infinity Console.WriteLine(1.0 / -0); // -Infinity
1.5 浮點(diǎn)數(shù)比較正確姿勢(shì)
- 近似比較(epsilon 容差)
bool IsEqual(double a, double b, double eps = 1e-10)
=> Math.Abs(a - b) < eps;
- 游戲開(kāi)發(fā)常見(jiàn)做法(Godot / Unity)
Mathf.Approximately(a, b); // Unity Mathf.IsEqualApprox(a, b); // Godot
- 避免直接用
==
除非數(shù)據(jù)本身是整數(shù)運(yùn)算得來(lái)的,或者特別確定是完全相等。
2?? 定點(diǎn)數(shù)(decimal)
2.1 表示方法
- 總共 128 位存儲(chǔ):
- 96 位存有效數(shù)字
- 16 位存小數(shù)位精度(scale,小數(shù)點(diǎn)位置)
- 十進(jìn)制方式存儲(chǔ) → 可以精確表示
0.1、0.2、0.3。
2.2 特點(diǎn)
- 高精度(28-29 位有效數(shù)字)
- 范圍比
double小,但能避免浮點(diǎn)誤差 - 計(jì)算速度比浮點(diǎn)數(shù)慢(大約 5~20 倍),因?yàn)槭擒浖?shí)現(xiàn)而不是硬件指令
2.3 示例
decimal a = 0.1m + 0.2m; decimal b = 0.3m; Console.WriteLine(a == b); // True
?? 在貨幣、金融計(jì)算中,應(yīng)優(yōu)先使用 decimal。
3?? 性能對(duì)比
| 特性 | float/double(浮點(diǎn)數(shù)) | decimal(定點(diǎn)數(shù)) |
|---|---|---|
| 存儲(chǔ)方式 | 二進(jìn)制科學(xué)計(jì)數(shù)法 | 十進(jìn)制定點(diǎn)數(shù) |
| 精度 | 有誤差(約 15~16 位) | 高精度(28~29 位) |
| 范圍 | 極大 | 較小 |
| 運(yùn)算速度 | 硬件支持,速度極快 | 慢(軟件實(shí)現(xiàn)) |
| 適用場(chǎng)景 | 科學(xué)計(jì)算、物理模擬 | 金融、貨幣 |
4?? 小結(jié)
- 浮點(diǎn)數(shù) → 范圍大、速度快,但存在精度誤差
- decimal → 精度高,適合金融,但性能較差
- 判斷浮點(diǎn)數(shù)相等時(shí),應(yīng)使用 近似比較 而不是
== - 在游戲或物理模擬 → 用
float/double - 在賬務(wù)、價(jià)格計(jì)算 → 用
decimal
到此這篇關(guān)于C# 浮點(diǎn)數(shù)與定點(diǎn)數(shù)詳細(xì)解析的文章就介紹到這了,更多相關(guān)C# 浮點(diǎn)數(shù)與定點(diǎn)數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
WPF使用Dragablz構(gòu)建可拖拽分離的Tab頁(yè)程序
這篇文章介紹了WPF使用Dragablz構(gòu)建可拖拽分離Tab頁(yè)的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
C#語(yǔ)法相比其它語(yǔ)言比較獨(dú)特的地方(一)
這篇文章主要介紹了C#語(yǔ)法相比其它語(yǔ)言比較獨(dú)特的地方(一),本文講解了switch語(yǔ)句可以用來(lái)測(cè)試string型的對(duì)象、多維數(shù)組、foreach語(yǔ)句、索引器和Property等內(nèi)容,需要的朋友可以參考下2015-04-04
c#判斷數(shù)據(jù)庫(kù)服務(wù)器是否已經(jīng)啟動(dòng)的方法
這篇文章主要介紹了使用c#判斷數(shù)據(jù)庫(kù)服務(wù)器是否已經(jīng)啟動(dòng)的方法,大家參考使用吧2014-01-01
Unity Shader實(shí)現(xiàn)翻書(shū)效果
這篇文章主要為大家詳細(xì)介紹了Unity Shader實(shí)現(xiàn)翻書(shū)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
C#創(chuàng)建安全的棧(Stack)存儲(chǔ)結(jié)構(gòu)
這篇文章主要為大家詳細(xì)介紹了C#創(chuàng)建安全的棧(Stack)存儲(chǔ)結(jié)構(gòu)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10

