C浮點數據格式[轉]

#include <stdio.h>

int main(int argc, char *argv[])
{
    float p = 5.1f;
    int f = (int)(p*100);
    printf("%d", f);
    getch( );
    return 0;
}

我想要輸出 510,可是機器nnd居然輸出509(竟然敢扣我工錢)。
到底是what's wrong。我上看下看,左看又看,看了又看,就是發現不了錯誤。
於是我試着把5.1改成5.5,一切正常啊。搗鼓了N個小時後猜想,莫非是浮點數的表示問題,
於是花了很久找到浮點數的機器表示方法,照着規定克隆操作了一下。(據說練過乾坤大
挪移的人什麼招式都可以克隆)。

IEEE規定的浮點數的機器表示:

32位機器的 float 是4字節的,共32位。
第1位是符號位,接着8位指數位,接着23位基數位。
以5.1爲例。

5 = 101 (2進制)

0.1 = 0.0 0011 0011 0011 0011 0011 0011 .....(無限循環)

所以 5.1 = 101.0 0011 0011 0011 0011 0011 0011 0011 0011 ...

5.1= 1.010 0011 0011 0011 0011 0011 0011 0011 0011 0011... * 2^2

因爲第一位總是爲1,如果是0,就移動小數點直到是非0的,所以第一位的1丟棄。
得到 010 0011 0011 0011 0011 0011 0011 0011 0011....
取23位 得到 0100 0110 0110 0110 0110 011

接着看指數部分
指數是2, 根據規定,指數統一+127再轉換爲無符號8位2進制數,
2+127=129 (1000 0001)

存儲的時候指數部分存儲在基數之前,這樣就有31位了,
因爲5.1是正的,所以符號爲是0,存儲在指數部分之前

這樣就得到 0100 0000 1010 0011 0011 0011 0011 0011

我們來看一下機器上是否真的如此

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    float a=5.1;
    int *i=&a;
    printf("%x", *i);
    system("PAUSE");
    return 0;
}

40a33333
0100 0000 1010 0011 0011 0011 0011 0011

果真是一樣的。

這個例子就說明了爲什麼浮點數有時存在這樣的問題。
這個數化爲10進制整數的時候,
由於不可能達到5.1(5.099..)
所以×100後截取了前面的值 509。 

 

 

32位機器上float 的表示
對於大小爲32-bit的浮點數(32-bit爲單精度,64-bit浮點數爲雙精度,80-bit爲擴展精度浮點數),
1、其第31 bit爲符號位,爲0則表示正數,反之爲複數,其讀數值用s表示;
2、第30~23 bit爲冪數,其讀數值用e表示;
3、第22~0 bit共23 bit作爲係數,視爲二進制純小數,假定該小數的十進制值爲x;

則按照規定,該浮點數的值用十進制表示爲:
= (-1)^s * (1 + x) * 2^(e - 127)

對於49E48E68來說,
1、其第31 bit爲0,即s = 0
2、第30~23 bit依次爲100 1001 1,讀成十進制就是147,即e = 147。
3、第22~0 bit依次爲110 0100 1000 1110 0110 1000,也就是二進制的純小數0.110 0100 1000 1110 0110 1000,其十進制形式爲0.78559589385986328125,即x = 0.78559589385986328125。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章