Java中float/double取值范围与精度
Java浮點數
浮點數結構
要說清楚Java浮點數的取值范圍與其精度,必須先了解浮點數的表示方法,浮點數的結構組成,之所以會有這種所謂的結構,是因為機器只認識01,你想表示小數,你要機器認識小數點這個東西,必須采用某種方法,比如,簡單點的,float四個字節,前兩個字節表示整數位,后兩個字節表示小數位(這就是一種規則標準),這樣就組成一個浮點數。而Java中浮點數采用的是IEEE 754標準。
IEEE 754
這里就不細說什么是IEEE 754了,就直接講具體內容,有興趣的可以自己百度。
float
| 符號位(S):1bit | 指數位(E):8bit | 尾數位(M):23bit |
一個float4字節32位,分為三部分:符號位,指數位,尾數位。
(1).符號位(S):最高位(31位)為符號位,表示整個浮點數的正負,0為正,1為負;
(2).指數位(E):23-30位共8位為指數位,這里指數的底數規定為2(取值范圍:0~255)。這一部分的最終結果格式為:2E−127,即范圍-127~128。另外,標準中,還規定了,當指數位8位全0或全1的時候,浮點數為非正規形式(這個時候尾數不一樣了),所以指數位真正范圍為:-126~127。
(3).尾數位(M):0-22位共23位為尾數位,表示小數部分的尾數,即形式為1.M或0.M,至于什么時候是1,什么時候是0,則由指數和尾數共同決定。 小數部分最高有效位是1的數被稱為正規(規格化)形式。小數部分最高有效位是0的數被稱為非正規(非規格化)形式,其他情況是特殊值。 最終float的值 =(−1)S∗(2E−127)∗(1.M)。具體形式如下:
|
符號 |
指數 部分 |
指數部分-127 |
尾數部分 |
小數部分的 最高有效位 |
形式 |
|
1 |
255 |
128 |
非0 |
沒有 |
NaN |
|
1 |
255 |
128 |
0 |
沒有 |
負無窮 |
|
1 |
1~254 |
-126~127 |
任意 |
1 |
正規形式(負數) |
|
1 |
0 |
-127 |
非0 |
0 |
非正規形式(負數) |
|
1 |
0 |
-127 |
0 |
沒有 |
負0 |
|
0 |
0 |
-127 |
0 |
沒有 |
正0 |
|
0 |
0 |
-127 |
非0 |
0 |
非正規形式(正數) |
|
0 |
1~254 |
-126~127 |
任意 |
1 |
正規形式(正數) |
|
0 |
255 |
128 |
0 |
沒有 |
正無窮 |
|
0 |
255 |
128 |
非0 |
沒有 |
NaN |
double
| 符號位(S):1bit | 指數位(E):11bit | 尾數位(M):52bit |
double這里就類似float,只是double的長度更大,所以范圍就更大,但規則是一樣的。double的值 =(−1)S∗(2E−1023)∗(1.M)。
取值范圍
根據表1可知,float的取值范圍:
負無窮 ——−2128~~~−2−149—— 0 ——2−149~~2128—— 正無窮
1). 上面的“——”表示中間不能取值,例如負無窮到−2128中間的值是取不到的(事實上128也是取不到的,只是接近近似值),但這并不是意味著,“~”任意值都能取到的,要注意,浮點數都是有精度的,并不能表示絕對值任意小的值。另外,Java中無窮大表示為:
Float.POSITIVE_INFINITY或Double.POSITIVE_INFINITY//表示正無窮大
Float.NEGATIVE_INFINITY或Double.NEGATIVE_INFINITY//負無窮大
//他們打印的結果:+/-Infinity
float f1 = (float)Math.pow(2,128);//指數>=128的,打印結果:Infinity
//上面要加(float)強制轉換,否則編譯提示出錯,詳細可參考前一節:Java變量數據類型
float f2 = (float)Math.pow(2,127);//1.7014118E38
System.out.println(Float.MAX_VALUE);//3.4028235E38
//其他測試,讀者可自行測試
1
2
3
4
5
6
7
8
2). -149的得來:看上面理論應該是150(指數全0,則指數值 = 0 -127,這個時候尾數取最小,2−23,則-127-23 = -150),可不知道為什么是149,我查到的資料是說,全0,全1為特殊值,不作為范圍內的值,上面的float的最大最小值Float.MAX_VALUE都是接近2128)。故值 =(−1)S∗(2−126)∗(2−23)= +/-2−149
float f3 = (float) Math.pow(2,-149)//1.4E-45,小于-149,結果則為0.0
Float.MIN_VALUE //1.4E-45
1
2
double的取值同float:
負無窮 ——−21024~~~−2−1074—— 0 ——2−1074~~21024—— 正無窮
1074 =| (-1022) - (52)|
另外,注意表格中,還有NaN,即表示非數值,例如:
System.out.println(0.0/0.0);//打印結果:NaN。注意不能是 0/0
//NaN表示計算錯誤,具體出現情況,可以參考表中
//Float.NaN或 Double.NaN 也能直接表示NaN,NaN與其他數計算結果均為NaN,除了
Math.pow(Float.NaN,0);//結果為1.0
//另外NaN == NaN; false
1
2
3
4
5
浮點數精度
精度是由尾數決定的,為什么?由浮點數的值計算公式可知:當指數的最終值為負,雖然這個時候浮點數的值能表示更小,但這個時候僅僅能表示0~1(或-1~0)這個數段的小數,沒有實際意義。所以精度主要是看尾數的值。
float
float的尾數:23位,其范圍為:0~223,而223=8388608=106.92,所以float的精度為6~7位,能保證6位為絕對精確,7位一般也是正確的,8位就不一定了(但不是說8位就絕對不對了),注意這里的6~7位是有效小數位(大的數你先需要轉換成小數的指數形式,例如:8317637.5,其有效小數位:8.3176375E6,七位),而有效位(從第一個不為0的開始數)是7~8位,是包括整數位的,像8317637.5,你不轉換,則要從有效位的角度來看,有8位有效位。
System.out.println((float)Math.pow(10,6.92));//注意加float強制轉換
//打印結果8317637.5,float只保證7~8位有效位,其余位數舍入
1
2
不理解的話,可以再這樣想:23位,二進制0101……0101,尾數表示小數位,最小為0000……0001(22個0,最后一個1),即2−23=1.1920929E-7 ,這是float的最小單元(大概是0.0000001192大小,你想表示比這更小的,比如0.00000001,不可能啊),這是一個7位小數位小數,最小就是這么小,比這個更小的,計算機就無能為力了,比這個更大的,每次通過加這么一個最小單元,直到相等或接近(兩個相差一個最小單元的數,它們之間的數也是不能表示的,所以有的7位也是不能精確的,因為最小不是0.0000001,而是比這個稍大)。
double
計算方式同float,double的尾數:52位,2−52=2.220446049250313E-16,最小是16位,但最小不是1.0E-16,所以精度是15~16,能保證15,一般16位。
更多關于Java浮點數的,可以參考這里:基礎野:細說浮點數(肥子John)
總結
以上是生活随笔為你收集整理的Java中float/double取值范围与精度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图解Apache Mina
- 下一篇: Dorado