如下c#**:
float a = 0.65f;
float b = 0.6f;
float c = a - b;
此時c為多少?
0.05?錯誤!
此時c為0.0499999523!
為什麼?
其根本原因是計算機所使用二進位制01**無法準確表示某些帶小數字的十進位制資料。
下面我們來分析下:
我們知道將乙個十進位制數值轉換為二進位制數值,需要通過下面的計算方法:
1. 整數部分:連續用該整數除以2,取餘數,然後商再除以2,直到商等於0為止。然後把得到的各個餘數按相反的順序排列。簡稱"除2取餘法"。
2. 小數部分:十進位制小數轉換為二進位制小數,採用"乘2取整,順序排列"法。用2乘以十進位制小數,將得到的整數部分取出,再用2乘餘下的小數部分,然後再將積的整數部分取出,如此進行,直到積中的小數部分為0或者達到所要求的精度為止。然後把取出的整數部分按順序排列起來,即先取出的整數部分作為二進位制小數的高位,後取出的整數部分作為低位有效位。簡稱"乘2取整法"。
3. 含有小數的十進位制數轉換成二進位制,整數、小數部分分別進行轉換,然後相加。
例如:將十進位制數值25.75轉換為二進位制數值,步驟如下:
25(整數部分)
25/2=12......1
12/2=6.......0
6/2=3......0
3/2=1......1
1/2=0......1
(25) 10=(11001) 2
0.75(小數部分)
0.75*2=1.5......1
0.5*2=1......1
(0.75) 10=(0.11) 2
(25.75) 10=(11001) 2+(0.11) 2=(11001.11) 2
按照上述方法,我們將0.65及0.6轉換為二進位制**:
(0.65)10 = (0.101001100110011001100110011001100110011......)2
(0.6) 10 = (0.10011001100110011001100110011001100110011......)2
後面的省略號表示已經算不完了,後面在無限重複 0011 這段二進位制數值。
文章開始部分,我們用的float型別,下面我們來看看float型別是否能儲存上面轉換出的二進位制**。
目前計算機上儲存浮點數值是按照ieee(電氣和電子工程師協會)754浮點儲存格式標準來儲存的。
ieee單精度浮點格式共32位,包含三個構成字段:23位小數f,8位偏置指數e,1位符號s。將這些字段連續存放在乙個32位字裡,並對其進行編碼。其中0:22位包含23位的小數f; 23:30位包含8位指數e;第31位包含符號s。如下圖所示:
也就是說上面將0.65及0.5轉換出的二進位制**,我們只能儲存23位,即使資料型別為double,也只能儲存52位,這樣大家便能看出問題出現的原因了。
擷取的二進位制**已無法正確表示0.65及0.5,根據這個二進位制**肯定無法正確得到結果0.05。
如何解決這個問題?知道其根本原因後,我們知道是無法從根本上解決這個問題的,但我們可以有一些曲線救國的方法,下面列舉幾個:
1. 因為二進位制數值可以準確表示整數(可以使用整數轉換為二進位制方法驗證下),所以可以將小數乘以10或100等變成整數,然後做運算,最後再通過除以10或100等獲得結果;
2. 通過擷取結果的有效小數字數等,來取得最好的近似結果,然後在做處理。
3. 對於可以用有限長度的二進位制數值表示的十進位制數值,可以使用儲存位數大於其長度的資料型別。
解決方案正在補充中……,若各位有什麼好的方法也可以提出來!
以上解決方案需要按照使用的實際情況來決定使用哪種方法。
PHP浮點運算結果出現誤差原因分析及解決方案
如下 float a 0.65f float b 0.6f float c a b 此時c為多少?0.05?錯誤!此時c為0.0499999523!為什麼?其根本原因是計算機所使用二進位制01 無法準確表示某些帶小數字的十進位制資料。下面我們來分析下 我們知道將乙個十進位制數值轉換為二進位制數值,需...
為什麼浮點型運算結果會有誤差?
如var a 0.65 var b 0.6 console.log a b 0.05?錯 a b 0.050000000000000044為什麼?其根本原因在於計算機所使用的01 無法準確地表示某些帶小數的十進位制資料。下面我們來分析下 我們知道將乙個十進位制數值轉換為二進位制數值,需要通過下面的計...
為什麼浮點型運算結果會有誤差?
如var a 0.65 var b 0.6 console.log a b 0.05?錯 a b 0.050000000000000044 為什麼?其根本原因在於計算機所使用的01 無法準確地表示某些帶小數的十進位制資料。下面我們來分析下 我們知道將乙個十進位制數值轉換為二進位制數值,需要通過下面的...