java浮點數儲存
面試題:
public class FloatDouble {
public static void main(String[] args) {
float f_v1 = 20;
float f_v2 = 20.3f;
float f_v3 = 20.5f;
double d_v1 = 20;
double d_v2 = 20.3;
double d_v3 = 20.5;
System.out.println((f_v1 == d_v1)?"true":"false" );
System.out.println(f_v2 == d_v2?"true":"false");
System.out.println(f_v3 == d_v3?"true":"false");
}
}
執行結果會是怎樣的呢?, 解釋執行結果的原因
這裡涉及到浮點數是如何儲存的.
- 如何將十進位制轉換成二進位制浮點數呢, 先介紹一下十進位制的浮點數 轉換二進位制的浮點數
分為兩部分:
-
先將整數部分轉換為二進位制,
-
將小數部分轉換為二進位制, 然後將整數部分與小數部分相加。
以 20.5 轉換為例,
20轉換後變為 10100
0.5 要轉換二進位制,需要乘2, 乘完之後取整數部分,然後用乘的結果減去整數部分, 然後接著乘2, 直至最後沒有小數或者小數出現迴圈, 即乘完.
如果等於0, 就取前面不為0的部分.
0.5 * 2 = 1.0 (取1)
0 * 2 = 0 (0)
所以, 轉換後 0.5 = 0.1,
所以 20.5 轉換二進位制後, 20.5 = 10100.1(二進位制)
再看一個浮點數 20.3
20 = 10100 (二進位制)
0.3 * 2= 0.6 (0)
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,進入迴圈了,所以,結果
0.3 = 0.010011001…1001
所以20.3 = 10100.010011001…1001 (二進位制).
2.如果要把十進位制浮點數,儲存到記憶體空間中,也就是4個位元組中,首先要把浮點數轉換成二進位制的浮點數, 然後再轉換成科學計數法.
這裡 20.5 = 10100.1(二進位制) = 1.01001E4(十進位制科學計數) = 1.01001E100(二進位制科學計數), 這裡E100指2的100次方
在java中,float 型別 數,佔4個位元組, 儲存結構如下
符號位: 1
指數位: 8
尾數位: 23, 如下圖所示
double 型別數, 佔8個位元組, 儲存結構如下
符號位:1
指數位:11
尾數位: 52
儲存資料是一個蘿蔔一個坑, 首先儲存符號位, 然後是 指數,最後尾數
比如20.5 = 1.01001E100(二進位制)
這裡使用到移位儲存, 對於float 數值來說, 指數位要加上127, 即0111111(二進位制)
00000100
+01111111
1000 0011
對於double 數值來說, 指數位要加上1023, 即0111 111 1111(二進位制)
0000 000 0100
- 0111 111 1111
1000 000 0011
所以20.5 儲存的數值 是 (float): 0-10000011-01001 00000 00000 00000 000
(double):0-10000000011-01001+(47個0)
這裡尾數位需要52位
現在看到20.5 轉換為float, double 的二進位制數, 指數和尾數是不同的, 注意,比較指數時 float 型會-127, double型 會-1023,因此
float 型又變成了00000100
double型又變成0000000100 ,這時候比較,因為兩個指數的位數不同,一個8位,一個10位,8位的數會在前面自動補0
比較尾數時,float型數會自動在後面補0直至與double 型相同的52位
同理20.3 儲存的數值 是: (float) 0-10000011-01001 10010 10011 00101 001
(double)0-1000000011-01001(後面迴圈1001, 直至尾數為52位)
與20.5的比較相似, 20.3的float型二進位制和double型二進位制,符號位與指數位都相同, 但是尾數位不相同,float型到了23位之後都是0, double型一直1001迴圈到52位. 這就是float型與double型比較之後不相等的原因
如果要將三個比較結果 都為true, 需在d_v2加上 (float), 也就是將double強制轉為float型