關於數據精度的一點總結


說到數據精度,不得不說的,就是數據長度。

這里聊了一下float這個類型,float占4個字節,共4*8=32位。下圖是float在內存格式:

31:標志位,0表示正數,1表示負數。30-23:指數位,共8位。22-0:小數位,共23位。

 

示例:12345 = ‭0011 0000 0011 1001‬ = 1.1 0000 0011 1001 * 2^13

13為指數,存放到指數位。指數可正可負,所以這8位需要表示-127至128。本例中13保存為13+127 = 140 = ‭1000 1100‬。

1.1 0000 0011 1001存放在小數位,由於小數點前永遠都是1,所以可以省略,只存1 0000 0011 1001,不足23位,后面補0,即保存為1 0000 0011 1001 0000 0000 00

最終保存結果:0 ‭1000 1100‬ 1 0000 0011 1001 0000 0000 00

 

回過頭來,再看12345字個數,二進制為1.1 0000 0011 1001 * 2^13,如果小數部份長度超過23位,就無法完整保存了,只能舍棄多余的部份。

比如1.1 0000 0011 1001 0000 0000 001*2^24,藍色長度為23,實際保存時,只有藍色部份會保存。

那么這個數,就與1.1 0000 0011 1001 0000 0000 000*2^24在內存中是一樣的,但我們知道,這兩個數肯定是不一樣的,精度丟失!

 

按上述結論,float在整數范圍內,精度能完全保存的最大值是1.1111 1111 1111 1111 1111 111*2^23,即1111 1111 1111 1111 1111 1111 = ‭16777215‬。

這個數+1,就成了1 0000 0000 0000 0000 0000 0000 = 1.0000 0000 0000 0000 0000 0000*2^24 = 167772156。

再+1,就成了1 0000 0000 0000 0000 0000 0001 = 1.0000 0000 0000 0000 0000 0001*2^24 = 167772157。

由於小數長度有23位這個限制,上述的兩個數,紅色部份都不會保存,即167772156和167772157在內存中保存是一樣的: 167772156  =  167772157

 

驗證:

int main(int argc, char *argv[])
{
    float j,k;
    j = 16777216;
    k = 16777217;
    cout << j << endl;
    cout << k << endl;
    printf("%f\n",j);
    printf("%f\n",k);
    cout << (j=k?1:0) << endl;
    return 0;
}

輸出:

1.67772e+007
1.67772e+007
16777216.000000
16777216.000000
1

 

如果不考慮精度的問題,float能保存的最大值是1.1111 1111 1111 1111 1111 111(1 1111 1111 …… 1111 共128-23=105個1)*2^128 = 3.4028236692093846346337460743177e+38。

由於紅色部份不會保存,因此這105位可以是1和0的任意組合,但他們最終都保存為1.1111 1111 1111 1111 1111 111*2^128,僅當這105位都為0,才沒有丟失精度,即有2^105-1個數都丟失精度。

 

float如此,double也一樣,只不過double長度為8個字節,可以存儲更精確的數據,但數據精度仍然是數據存儲時,不能回避的問題,所以在開發過程中,一定要選好正確的數據類型,以滿足業務的需要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM