float爲何比int表示的範圍廣?java
什麼是單精度和雙精度?數據庫
float表示小數的時候爲何會有精度丟失?函數
帶着這幾個問題,咱們來探究下java中float類型在計算機的表示形式。ui
java中int佔用4個字節,float也是佔用4個字節,可是爲何float表示的範圍要比int大呢,由於二者在計算機內中表示的方式不同,int是4個字節32位,每一位都是二進制小數表示,最高位0表明是正數,最高位爲1表明是負數,因此int的範圍是-2^31~2^31-1;spa
float也是4個字節,遵循IEEE-754格式標準,在計算機中表示有三個部分組成:符號s底數m和指數e。ci
符號s:最高位,0爲正數;1爲負數,佔用一位;字符串
指數e:是該浮點數的指數,二進制表示,最高位爲指數符號爲1表示大於1,0表示小於1,其實他是用的偏移量表示的,偏移大小爲127,沒有用補碼錶示,佔用一個字節8位;rpc
底數m:是該浮點數的實際值,二進制形式表示,m的範圍是【1,2】或者【0,1】佔用23位。it
因此float在計算機的表示以下面所示:io
SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM
咱們先說下10進制和二進制的快速轉換方法。
10進制整數2進制轉換是除2求商和餘數,好比十進制17的二進制計算爲:
17 /2=16餘1
16 /2= 8 餘0
8 /2= 4 餘0
4 /2= 2 餘0
2 /2= 1 餘0
1 /2= 0 餘1
一直計算到商爲0爲止,17的二進制表示就是:10001
10進制小數2進製表示是乘2求積,好比0.16的二進制計算爲:
0.16*2=0.32取0
0.32*2=0.64取0
0.64*2=1.28取1
0.28*2=0.56取0
0.56*2=1.12取1
0.12*2=0.24取0
。。。
因此0.16的二進制表示就是001010..... 一直循環下去,因此除非小數最後爲5才能*2取整,不然都會無線循環下去,這就是爲何浮點小數精度丟失的問題。
下面咱們距離來講明10進制浮點數在計算機的表示, 拿17.16來講:
1.首先爲正數,s爲0
2.二進制爲10001.0010100011110101....小數點左移4位爲1.00010010100011110101...
3.指數位爲4+127=10000011,因此指數位位10000011
4.因爲默認最左邊爲1,因此底數爲00010010100011110101...
5.最後17.16的二進制表示就是:01000001100010010100011110101......總共32位,後面的捨棄
再拿0.16舉例:
1.首先爲整數,s爲0
2.二進制爲0.0010100011110101......小數點右移4位爲1.0100011110101
3.指數位爲4+127=10000011,而後取反爲01111100,因此指數位位01111100
4.底數位0100011110101...
5.最後0.16的二進制表示就是:0011111000100011110101...
float的(正數)範圍:
最小值:Float.MIN_VALUE=1.4E-45 (2的-149次方:指數位127+底數22)
最大值:Float.MAX_VALUE=3.4028235E38 (2的128次方-1)
注意事項:
1.價格在數據庫中保存建議是無符號整形,避免在java轉換成浮點數時出現精度丟失的問題;
2.若是須要用浮點型數據進行運算,建議使用BigDecimal,可是BigDecimal的構造函數必定要使用字符串的,不然同樣會出現精度丟失的問題:BigDecimal(「123f」)而不是BigDecimal(123f)。
3.Float.MIN_VALUE是:1.4E-45,不是一個負數,double也是的。可是整型的MIN_VALUE都是負數
4.float的m只有23位,2^23=8388608,總共有7位10進制數字,因爲最左邊的1省略了,因此表示的有效數字最高精確度位7~8位,包括整數部分,8位後的數字確定不是準確的