JAVA 浮點數的範圍和精度

(一)IEEE754標準

IEEE 754 標準即IEEE浮點數算術標準,由美國電氣電子工程師學會(IEEE)計算機學會旗下的微處理器標準委員會發布。

 

以32位float數據爲例,在內存中的存儲形式是1bit的符號位(S),8bit表示指數部分(Exp),23表示小數部分的尾數(Fraction)。

表一 單精度浮點數在內存中存儲形式

1bit符號

8bit指數部分

23bit尾數

符號位——S取0時表示負數,取1時表示負數。

指數部分——使用所謂的偏正值形式表示,而不是補碼錶示,即指數部分採用一個無符號的正數值存儲。也就是說指數部分要表示的值等於實際存儲值減去一個固定值(對於單精度float類型,是127)。採用這種方式表示的目的是簡化比較,因爲,如果採用補碼錶示的話,全體符號位S和Exp自身的符號位將導致不能簡單的進行大小比較。因爲指數值的大小從0~255(0和255是特殊值),單精度的指數部分範圍是-127~+128(對應的,-127和128是特殊值)。

尾數部分——23bit尾數僅能表示小數部分的尾數,小數部分最高有效位由指數部分決定,具體見下表。小數部分最高有效位是1的數被稱爲正規形式。小數部分最高有效位是0的數被稱爲非正規形式,其他情況是特殊值。

表二 單精度浮點數表示規則

符號

指數

部分

指數部分-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

按照IEEE標準,除了 NaN 以外,浮點數集合中的所有元素都是有序的。如果把它們從小到大按順序排列好,那順序將會是:負無窮,正規形式(負數)、非正規形式(負數)、負0、正0、非正規形式(正數)、正規形式(正數)、正無窮。

 

對於64bit的雙精度double類型,在內存中的存儲形式是1bit的符號位(S),11bit表示指數部分(Exp),52bit表示小數部分的尾數(Fraction)。指數部分的偏正值是1023,其他情況跟單精度類似,不再贅述。

(二)浮點數Q&A

1)浮點數可以表示數據的範圍是什麼?

不考慮特殊值(無窮大、NaN等),浮點數可以表示的範圍是[-Max,Max]。其中Max是浮點數能表示的最大值,具體值參見表三。

表三 浮點數最大值

浮點類型

字節碼

16進製表示

10進製表示

單精度

7f7fffff

0x1.fffffep127

3.4028235E38

雙精度

7fefffffffffffff

0x1.fffffffffffffp1023

1.7976931348623157E308

 

2)浮點數的精度怎樣衡量?

浮點數指數部分Exp的數值決定了浮點數與相鄰浮點數的差值,所以,指數部分越小(單精度最小爲-127),即浮點數絕對值越小(也就是浮點數越靠近0),相鄰浮點數的差值越小(單精度最小爲2^(-127)),浮點數能表示的有效小數位數越多。反之,指數部分越大(單精度最大爲127),即浮點數絕對值越大(也就是浮點數越遠離0),相鄰浮點數的差值越大(單精度最小爲2^(127)),浮點數能表示的有效小數位數越少。但是,從科學計算的角度看,不管指數部分的數值是多少,浮點數的有效位數由尾數部分決定,單精度的有效數是7位,雙精度的有效數是16位。

表四 浮點數最小正數

浮點類型

字節碼

16進製表示

10進製表示

單精度最小正數

00000001

0x0.000002p-126

1.4E-45

雙精度最小正數

0000000000000001

0x0.0000000000001p-1022

4.9E-324

3)我們知道,在Java中,存在基本數據類型的自動轉換,比如,直接將一個整形字面量賦給一個float變量。 那麼,在自動轉換後,整形的精度會丟失麼?

當浮點集中沒有與整形值對應的浮點數時,會將整形值轉化成最接近的浮點值,此時,整形值會丟失精度。例如下面的例子,數值爲33554431的整形轉化成單精度浮點數後,變成3.3554432E7,即33554432。

int intValue = Integer.MAX_VALUE >> 6;// 33554431

float floatFromInt = intValue;

System.out.println(floatFromInt);// 3.3554432E7

System.out.println(intValue);// 33554431

 

最後附查看某些浮點數字節碼、16進製表示、10進製表示的源碼及運行結果。

單精度源碼及結果。 

 

 1 package com.wsm.test;
 2 
 3 public class TestFloat {
 4 
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9 
10         int intValue = Integer.MAX_VALUE >> 6;// 33554431
11         float floatFromInt = intValue;
12         System.out.println(floatFromInt);// 3.3554432E7
13         System.out.println(intValue);// 33554431
14 
15         System.out.printf("%-12s\t%-20s%-12s%-20s\n", "描述", "十六進制數",
16                 "        字節碼", "            十進制數");
17         print("正        無         窮", Float.POSITIVE_INFINITY);
18         print("最        大         值", Float.MAX_VALUE);
19         print("最小正規形式正數", Float.MIN_NORMAL);
20         print("最大非正規形式值", +0x0.fffffep-127f);
21         print("最    小      正    數", Float.MIN_VALUE);
22         print("負         無        窮", Float.NEGATIVE_INFINITY);
23         print("規     範     的 NaN", Float.NaN);
24         print("其     他     的 NaN", Float.intBitsToFloat(Integer
25                 .valueOf(0xffc54321)));
26 
27     }
28 
29     static void print(String describe, float floatNum) {
30         System.out.printf("%-12s\t%-20s%-12s%-20s\n", describe, Float
31                 .toHexString(floatNum), insertZero(Integer.toHexString(Float
32                 .floatToRawIntBits(floatNum)), 8), floatNum);
33     }
34 
35     static String insertZero(String input, int length) {
36         StringBuilder sb = new StringBuilder(input);
37         while (sb.length() < length) {
38             sb.insert(0, "0");
39         }
40         return sb.toString();
41     }
42 }

3.3554432E7
33554431
描述           十六進制數                       字節碼             十進制數   
正        無         窮 Infinity            7f800000    Infinity           
最        大         值 0x1.fffffep127      7f7fffff    3.4028235E38       
最小正規形式正數     0x1.0p-126          00800000    1.17549435E-38     
最大非正規形式值     0x0.8p-126          00400000    5.877472E-39       
最    小      正    數 0x0.000002p-126     00000001    1.4E-45            
負         無        窮 -Infinity           ff800000    -Infinity          
規     範     的 NaN NaN                 7fc00000    NaN                
其     他     的 NaN NaN                 ffc54321    NaN                

雙精度源碼及結果。 

 

 1 package com.wsm.test;
 2 
 3 public class TestDouble {
 4 
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9 
10         System.out.printf("%-12s\t%-30s%-24s%-40s\n", "描述", "十六進制數",
11                 "                  字節碼",
12                 "                                   十進制數");
13         print("正        無         窮", Double.POSITIVE_INFINITY);
14         print("最        大         值", Double.MAX_VALUE);
15         print("最小正規形式正數", Double.MIN_NORMAL);
16         print("最大非正規形式值", +0x0.fffffffffffffp-1023d);
17         print("最    小      正    數", Double.MIN_VALUE);
18         print("負         無        窮", Double.NEGATIVE_INFINITY);
19         print("規     範     的 NaN", Double.NaN);
20         print("其     他     的 NaN", Double.longBitsToDouble(Long
21                 .valueOf(0xfff8000000054321L)));
22 
23     }
24 
25     static void print(String describe, Double DoubleNum) {
26         System.out.printf("%-12s\t%-30s%-24s%-40s\n", describe, Double
27                 .toHexString(DoubleNum), insertZero(Long.toHexString(Double
28                 .doubleToRawLongBits(DoubleNum)), 16), DoubleNum);
29     }
30 
31     static String insertZero(String input, int length) {
32         StringBuilder sb = new StringBuilder(input);
33         while (sb.length() < length) {
34             sb.insert(0, "0");
35         }
36         return sb.toString();
37     }
38 }

 

描述           十六進制數                                           字節碼                                      十進制數
正        無         窮 Infinity                      7ff0000000000000        Infinity                               
最        大         值 0x1.fffffffffffffp1023        7fefffffffffffff        1.7976931348623157E308                 
最小正規形式正數     0x1.0p-1022                   0010000000000000        2.2250738585072014E-308                
最大非正規形式值     0x0.8p-1022                   0008000000000000        1.1125369292536007E-308                
最    小      正    數 0x0.0000000000001p-1022       0000000000000001        4.9E-324                               
負         無        窮 -Infinity                     fff0000000000000        -Infinity                              
規     範     的 NaN NaN                           7ff8000000000000        NaN                                    
其     他     的 NaN NaN                           fff8000000054321        NaN                                    

參考資料:

1、IEEE754百度百科

2、《Java虛擬機規範(Java SE 7)》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章