java 浮點數表示法


 

這個要從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 mask 0x7ff0000000000000L) represent the exponent. Bits 51-0 (the bits that are selected by the mask 0x000fffffffffffffL) 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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM