• 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;

  • 相关阅读:
    面试题39:二叉树的深度、判断二叉树是不是平衡
    Bridge 桥接
    Adapter 适配器
    search_request.go
    scoring_criteria.go
    index_init_oprions.go
    index.go
    engine_init_options.go
    document_index_data.go
    util.go
  • 原文地址:https://www.cnblogs.com/zhangxuezhi/p/12036700.html
Copyright © 2020-2023  润新知