如何理解IEEE 754標準對Java中float值和double值的規定
在Java語言中,我們可以使用float和double這兩種基本數據類型來表示特定的數據。
這兩種數據類型,本質上是浮點數(floating-point number),浮點是一種對於實數的近似值數值表現法,由一個有效數字加上冪數來表示。
之所以使用浮點數,是因為計算機在使用二進制運算的過程中,無法將所有的十進制小數準確的換算為二進制,只能使用近似值來表示。
使用浮點數表示數值的方法很多,在Java中,和C語言一樣,float和double都采用了使用最為廣泛的IEEE 754標準。
IEEE 754標準的全稱為IEEE二進制浮點數算術標準(ANSI/IEEE Std 754-1985),其中ANSI是美國國家標準學會(American National Standards Institute)的縮寫,IEEE是電器電子工程師學會(Institute of Electrical and Electronics Engineers)的縮寫,754是該標準的編號,1985則是該標準發布的年份。
IEEE 754規定,一個二進制浮點數在存儲中由三部分組成:
其中第一部分為符號位(sign bit),第二部分為指數偏移值(exponent bias)用於存儲浮點數的指數部分,第三部分為分數(fraction)用於存儲浮點數的有效數的小數部分。
以一個具體的float值為例,Java中的float值采用的是IEEE754中的單精度標準,使用32個比特進行存儲。例如:
0100 0100 1010 0110 1001 1110 0000 0000
其中:
0100 0100 1010 0110 1001 1110 0111 0100
第一位的0為符號位,它表示這個數的正負值為正,相應的,若第一位為1則表示這是一個負數;
0100 0100 1010 0110 1001 1110 0000 0000
第2~9的8個比特存儲的是指數偏移值
0100 0100 1010 0110 1001 1110 0000 0000
第10~32的23個比特存儲的是該float值的分數/小數部分。010 0110 1001 1110 0000 0000實際上表示的就是二進制的0.010 0110 1001 1110 0000 0000再加上1,也就是1.010 0110 1001 111。這實際上就是二進制的1010 0110 1001 111右移十四位的結果。1010 0110 1001 111在十進制中的值為21327,所以1.010 0110 1001 111也就等於21327*2^(-14)。
綜上,例子中的:
0100 0100 1010 0110 1001 1110 0000 0000
實際上也就等於:
+ 21327*2^(-14) * 2^10 = 1332.9375
第一位符號位表示 第10~32的分數位表示 第2~9的指數位表示
反之,例如我們想知道某個float a = 1000在內存中的形式,那麽則需要如下操作:
首先,1000是個整數,所以第一個比特位存儲的是0。
十進制的100在二進制中為11 1110 1000,這實際上就是1.111101左移9位的結果,
那麽實際上指數位存儲的結果就應該是9 + 127 = 136也就是1000 1000
分數位存儲的則是1.111101減去1的部分,補齊23位,也就是111 1010 0000 0000 0000 0000
綜上float a = 1000在內存中的存儲為:
0100 0100 0111 1010 0000 0000 0000 0000
另外,前面提到過的,指數偏移值為0或255的時候代表特殊值:
當指數值為0,即0000 0000時,若小數部分為0,則這個數為±0(正負由符號位決定);
當指數值為255,即1111 1111時,若小數部分為零,則這個數為±∞(正負由符號位決定);
當指數值為255,即1111 1111時,若小數部分非零,則這個數表示為不是一個數(Not a Number)。
以上就是float的部分,double同理,只不過double采用IEEE 754雙精度標準,使用64個比特存儲,其中2~12的11位為指數位,13~64的52位為小數位。
References:
IEEE 754 - wiki
https://zh.wikipedia.org/zh-cn/IEEE_754
浮點數 - wiki
https://zh.wikipedia.org/zh-cn/%E6%B5%AE%E7%82%B9%E6%95%B0
如何理解IEEE 754標準對Java中float值和double值的規定