這個要從Double類的一個方法說起:Double.doubleToLongBits(double value),根據官方文檔,其部分注釋內容如下:
public static long doubleToLongBits(double value)Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "double format" bit layout.Bit 63 (the bit that is selected by the mask
0x8000000000000000L
) represents the sign of the floating-point number. Bits 62-52 (the bits that are selected by the mask0x7ff0000000000000L
) represent the exponent. Bits 51-0 (the bits that are selected by the mask0x000fffffffffffffL
) represent the significand (sometimes called the mantissa) of the floating-point number.
個人翻譯一下:
根據IEEE 754浮點“double格式” 比特位的布局,返回一個浮點值。
bit63表示符號位,bits62-52表示指數域,bits51-0表示有效數字(尾數域)
關於 IEEE 754,可以參考該博客:https://blog.csdn.net/m0_37972557/article/details/84594879
現在做如下測試:
System.out.println(Double.doubleToLongBits(0.75));
System.out.println(Double.doubleToLongBits(0.5));
結果
0.75
十進制值:4604930618986332160
十六進制值:3FE8 0000 0000 0000
0.5
十進制值:4602678819172646912
十六進制值:3FE0 0000 0000 0000
對於0.75的十六進制,其符號位為0,指數域為3FE,尾數域為 8 0000 0000 0000
計算過程:
指數域0x3FE的十進制為:1022,而指數域的偏移碼是:1023,因此實際的指數值為:1022 -1023 = -1
對於尾數域,后面的一堆0不看,最左邊的值就是1,則表示其有效值為0.1,而尾數域的正規表示形式為:1.xxx(最左邊的1在轉換為浮點表示時會自動省略),因此尾數的實際值的計算方法是其有效值加1,即:1 + 0.1 = 1.1,該結果是二進制值
通過上面兩步,拿到了指數為-1, 位數為1.1(二進制)
結果計算3種方法,結果一致,都是0.75
小數點移位法:指數域為-1,表示尾數1.1的小數點往左移動一位,得出結果: 0.11,轉換成十進制就是:0.5 + 0.25 = 0.75
二進制相乘:指數域為-1,表示實際的指數結果為:2-1,即0.5,二進制表示為0.1,計算:1.1 * 0.1 = 0.11,十進制即0.75
十進制相乘:指數域為-1,表示實際的指數結果為:2-1,即0.5,而1.1的十進制表示為1.5,計算:1.5 * 0.5 = 0.75
同理:
0.5的十六進制中的有效數值3FE0,算出來指數域是-1,尾數域是0,結果為:0.1,轉為十進制:0.5
可以類推:
0.25的浮點表示為:0x3FD0 0000 0000 0000
-0.25的浮點表示為:0xBFD0 0000 0000 0000
0.625的浮點表示為:0x3FE4 0000 0000 0000
1.5的浮點表示為:0x3FF8 0000 0000 0000
-3.625的浮點表示為:0xC00D 0000 0000 0000
再來看下最開始提到的方法的源碼:
public static long doubleToLongBits(double value) { long result = doubleToRawLongBits(value); // Check for NaN based on values of bit fields, maximum // exponent and nonzero significand. if ( ((result & DoubleConsts.EXP_BIT_MASK) == DoubleConsts.EXP_BIT_MASK) && (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L) result = 0x7ff8000000000000L; return result; } public static native long doubleToRawLongBits(double value);
該方法的核心其所調用的native方法,但是還額外處理了一類特殊值:當指數域的值達到1024,即超出規定的1023值,並且尾數域不為0時,此時會返回一個固定值。在IEEE 754中,這樣的值是NaN,即not a number,不是一個數。
除此之外,IEEE 754還規定了另外兩個特殊值:正無窮和負無窮。對應的形式:指數域為1024,尾數域為0,符號位為正則正無窮,為負則負無窮。
除此之外,Double類還提供一個逆過程的方法如下,可以傳入浮點表示法的值(8個字節,所以要用long類型接收),然后返回實際的double值
public static native double longBitsToDouble(long bits);
這也是一個native方法,不知道是C++支持還是操作系統支持的這個方法。
因為雙精度浮點表示的指數最大值是1023,因此其可表示的最大值為:21023 * 0x1.FFFFFFFFFFFFF(13個F),約等於:1.7976931348623157e+308
在jdk1.8的源碼中,其表示如下:
public static final double MAX_VALUE = 0x1.fffffffffffffP+1023;