最近在學習資料型別的時候,遇到了浮點型資料精度丟失的問題,不是很理解,在這裡整理一下。
將乙個十進位制浮點數轉變為二進位制,可以整數部分和小數部分分開來看。
整數部分和十進位制整型資料轉二進位制的方法一樣,採用「除2取餘,逆序排列」法。具體做法是:用2去除十進位制整數,可以得到乙個商和餘數;再用2去除商,又會得到乙個商和餘數,如此進行,直到商為零時為止,然後把先得到的餘數作為二進位制數的低位有效位,後得到的餘數作為二進位制數的高位有效位,依次排列起來
例如將十進位制207變為二進位制
207 / 2 = 103 >> 1
103 / 2 = 51 >> 1
51 / 2 = 25 >> 1
25 / 2 = 12 >> 1
12 / 2 = 6 >> 0
6 / 2 = 3 >> 0
3 / 2 = 1 >> 1
1 / 2 = 0 >> 1
按照上述的餘數採取從低位到高位的順序排列,就得到11001111
整數轉換完就輪到小數部分。
十進位制小數轉換成二進位制小數採用「乘2取整,順序排列」法。具體做法是:用2乘十進位制小數,可以得到積,將積的整數部分取出,再用2乘餘下的小數部分,又得到乙個積,再將積的整數部分取出,如此進行,直到積中的小數部分為零,或者達到所要求的精度為止。然後把取出的整數部分按順序排列起來,先取的整數作為二進位制小數的高位有效位,後取的整數作為低位有效位。
例如將小數0.25變為二進位制
0.25 * 2 = 0.5 >> 0
0.5 * 2 = 1.0 >> 1
按照上述的整數字從高到低的順序排列,就得到0.01
結合上面提到的整數部分,可以得到十進位制207.25
轉變為二進位制為11001111.01
上面的操作看起來沒有啥問題,但是假如我想將十進位制小數0.6變為二進位制,就遇到了麻煩。
還是按照上面的方法進行轉換
0.6 * 2 = 1.2 >> 1
0.2 * 2 = 0.4 >> 0
0.4 * 2 = 0.8 >> 0
0.8 * 2 = 1.6 >> 1
0.6 * 2 = 1.2 >> 1
......
結果發現這是乙個無限迴圈的計算,也就是說小數點後面有無數字。但是我們都知道浮點數在記憶體中佔4個位元組,就算是雙精度型別也只是8個位元組,並不是無限大的。
所以可以得出下面的結論:
所以除了以5結尾的浮點數,以其餘數字結尾的浮點數是一定會失去精度的。而以5結尾的浮點數如果長度超過一定限度也是會失去精度的,至於這個長度是多少,需要我們看看浮點數到底在記憶體中是如何儲存的。
在儲存到記憶體前,我們首先要將二進位制的浮點數用乙個類似於科學技術表示法的標準去展示。根據ieee 754標準規定格式如下
v = (-1)s * m * 2e
其中,s表示符號位,0為正,1為負;m是有效數字,大於1小於2;e是指數,小數點的移動位數。
例如上面提到的207.25的二進位制表示11001111.01
就要表示為
11001111.01 = (-1)0 * 1.100111101 * 27
s=0m=1.100111101
e=7浮點型在記憶體中佔4個位元組,32bits。這32位是這麼分配的,從高到低
但是在儲存的時候m和e並不是原樣儲存的,同樣是根據ieee 754標準規定
這裡在低位補0而不是高位,因為不是為了取值,而只是為了取1和0的排列順序那麼上面提到的
11001111.01
儲存到記憶體中的時候
s=0m=100111101,擴充套件到23位為10011110100000000000000
e=7+127=134,二進位制表示為10000110
記憶體中最後表示為
01000011010011110100000000000000
這裡還有兩種特殊情況要說明
知道了記憶體中的儲存方式,就可以解釋第二種失去精度的現象了。
定義乙個整數0x00000009,變為浮點數卻返回0.000000?
首先將這個整數儲存為二進位制,也就是
00000000000000000000000000001010
可以看到e全為0,所以會返回0
雙精度在記憶體中佔8個位元組,區別就在於e和m的長度,對比**如下
符號位s
指數字e
小數部分m
指數偏移量
單精度浮點數
1位[31]
8位[30-23]
23位[22-00]
127雙精度浮點數
1位[63]
11位[62-52]
52位[51-00]
1023
綜上,總結起來下面兩種情況會失去精度
iOS解析json 浮點型資料,精度丟失問題
服務端傳遞回來的是 保留小數點兩位的浮點型,ios端解析後,發現 取出欄位的doublevalue後 精度丟失,小數點後多了很多位 原值 71.20 解析後 71.199997 複製 原始資料 複製 import nsnumbertest.h nsstring const kbigdecimalnu...
浮點型資料的精度控制問題
time limit 1 sec memory limit 16 mb submit 2380 solved 392 submit status web board 兩點確定一條直線,判斷一條直線與乙個圓的位置關係。輸入中前兩行每行描述乙個點的座標 x,y x,y均為實數。第三行包含三個實數,即圓心...
浮點型運算結果是不精確的,會出現精度丟失
float a 1.1f float b 3.1415926f double b 1.1d double result a b 結果是2.2000 0002 3841 858 解析 單精度有7 8位小數,雙精度有15位小數 二進位制儲存,單精度只有16個二進位制位,雙精度有64個二進位制位,二進位制...