目錄
存儲形式
存儲形式?不用多說,肯定是二進制啦!
IEEE 754 規定,對於 32 位的浮點數,最高位(第 31 位)是符號位 s,接着的 8 位(30 ~ 23)是指數 E,剩下的 23 位(22 ~ 0)爲有效數字 M,對於 64 位的浮點數,最高位(第 63 位)是符號位 s,接着的 11 位(第 62 ~ 52 位)是指數 E,剩下的 52位(第 51 ~ 0)爲有效數字 M。
SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
接下來就來砍一下:,一個 Float 在計算機中存儲是個啥亞子:
測試代碼
public static void testFloatStrore(String[] args) {
Float f = 20.3f;
System.out.println(Integer.toBinaryString(Float.floatToIntBits(f)));
}
運行結果:
可以看到 20.3f 存儲的值是有 31 位,因爲它是個正數,最高位爲0,省略。
轉換過程:
例:以上述測試的值 20.3 爲例
- 將值從十進制轉二進制:
整數部分:20 => 10100 (5 個 bit 位)
小數部分:
方式:
1)小數部分 乘 2,積的整數部分如果爲1;則計1,否則計0。
2)再對剩下的小數部分 乘 2,再計出 1 或 0 。
3)重複以上步驟,直至達到需要的精度。
0.3 => 01001100 11001100 1100...(無限循環)
合起來(最高位 0):10100.01001100 11001100 11001100 11...
- 小數點進行左移至小數點前只剩一位,值保持不變:1.0100010 01100110 01100110 0110011... * 2 ^ 4,左移了四位
- 浮點數有效位(底數): 因爲小數點前必爲1,IEEE 規定只記錄小數點後的位就好。
所以,此處的底數爲(從高位取 23 個位):01000100 11001100 1100110,
- 指數位:偏移量加上一個固定的偏移值 127,即:01111111
127 + 4 = 131 => 10000011
- 最終結果(符號位 、 指數位 、 浮點數有效位):0 10000011 01000100 11001100 1100110
!!!以補碼形式進行存儲
再來一例: 0.6f
運行上面的測試代碼後的輸出結果:
0.6 十進制轉二進制:0.10011001 10011001 1001...
上一步結果規格化: 右移 1 位,1.0011001 10011001 * 2 ^ -1,-1 + 127,即:126 => 01111110
0 01111110 00110011 00110011 0011001
指數位不全爲0,所以尾數附加位爲1,否則尾數附加位爲0
2^(126-127) * (2 ^ 0 + 2^-3 + 2^-4 + + 2^-7 + 2^-8 + 2^-11 + 2^-12 + 2^-15 + 2^-16)
但是,上面的測試代碼的運行結果和我們推算出的結果並不一致,推算出來的結果要比運行結果小 1 個 bit 位!
但是此處爲啥會出現這樣的結果?
Float 的尾數部分最多隻能表示 23 位。但是這個小數是個無限循環的,比如說 0.1f 爲了能表示 0.1f,只能模仿十進制進行四捨五入了,但二進制只有 0 和 1 , 於是變爲 0 舍 1 入。
參考資料:
http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html
https://github.com/sanshuiwang/Blog/issues/9