Skip to main content

JVM源码解读-Double类

finen...About 6 minJava-SourceJava-Source

1.类图

2.存储位置

  • Double类中的静态属性存储在方法区中的静态区。
  • 通过new Double()方法创建出来的对象存储在堆区。

3.了解IEEE 754

3.1 IEEE 754简介

该标准定义了浮点数的格式还有一些特殊值,它规定了计算机中二进制与十进制浮点数转换的格式及方法。规定了四种表示浮点数值的方法,单精确度(32位)、双精确度(64位)、延伸单精确度(43位以上)与延伸双精确度(79位以上)。
多数编程语言支持单精确度和双精确度,该标准的全称为IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985),又称IEC 60559:1989,微处理器系统的二进制浮点数算术(本来的编号是IEC 559:1989)。后来还有“与基数无关的浮点数”的“IEEE 854-1987标准”,有规定基数为2跟10的状况。最新标准是“ISO/IEC/IEEE FDIS 60559:2010”。
Double就是Java的双精度实现。

3.2 IEEE 754单精度浮点数表示

IEEE-754双精度浮点数(double floating-point)存储为64bit,由符号位(s)、有偏指数(e)、小数部分(f)组成:

组成描述位数位置
sign符号,0表示正,1表示负1bit63
exponent指数部分11bit52-62
fraction小数部分52bit0-51

11位的指数部分可存储00000000000 ~ 11111111111(十进制范围为0 ~ 2047),取值可分为3种情况:

11位指数不为00000000000和11111111111,即在00000000001 ~ 11111111110(1 ~ 2046)范围,这被称为规格化。
指数值为00000000000(0),这被称为非规格化
指数值为11111111111(2047),这是特殊值,有两种情况:
当52位小数部分f全为0时,若符号位是0,则表示+Infinity(正无穷),若符号位是1,则表示-Infinity(负无穷)
当52位小数部分f不全为0时,表示NaN(Not a Number)

3.1 属性说明

public final class Double extends Number implements Comparable<Double> {

    /**
     * 用来表示正无穷大,按照IEEE 754浮点标准规定,任何有限正数除以0为正无穷大,正无穷的值为0x7ff0000000000000L。
     * System.out.println(Double.POSITIVE_INFINITY == Double.longBitsToDouble(0x7ff0000000000000L)); => true
     * System.out.println(Double.POSITIVE_INFINITY); => Infinity
     */
    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
    
    /**
     * 用来表示负无穷大,任何有限负数除以0为负无穷的,负无穷的值为(0xfff0000000000000L)。
     * System.out.println(Double.NEGATIVE_INFINITY == Double.longBitsToDouble(0xfff0000000000000L)); => true
     * System.out.println(Double.NEGATIVE_INFINITY); => -Infinity
     */
    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
    
    /**
     * NaN 用来表示处理计算中出现的错误情况,比如0除以0或负数平方根。对于单精度浮点数,IEEE 标准规定 NaN 的指数域全为 1,且尾数域不等于零的浮点数。它并没有要求具体的尾数域,所以 NaN 实际上不非是一个,而是一族。Java这里定义的值为0x7ff8000000000000L。
     * System.out.println(Double.isNaN(Double.longBitsToDouble(0x7ff8000000000000L))); // true
     * System.out.println(Double.longBitsToDouble(0x7ff8000000000000L)); // NaN
     */
    public static final double NaN = 0.0d / 0.0;

    /**
     * MAX_VALUE 用来表示Double的最大值
     * System.out.println(Double.MAX_VALUE == Double.longBitsToDouble(0x7fefffffffffffffL)); // true
     * System.out.println(Double.longBitsToDouble(0x7fefffffffffffffL)); //1.7976931348623157E308
     */
    public static final double MAX_VALUE = 0x1.fffffffffffffP+1023; // 1.7976931348623157e+308

    /**
     * 保持 double -1022类型的最小正正常值的常量。
     * System.out.println(Double.MIN_NORMAL == Double.longBitsToDouble(0x0010000000000000L)); // true
     * @since 1.6
     */
    public static final double MIN_NORMAL = 0x1.0p-1022; // 2.2250738585072014E-308

    /**
     * 保持 double类型的最小正非零值的常量, 2^-1074
     * System.out.println(Double.MIN_VALUE == Double.longBitsToDouble(0x1L)); // true
     */
    public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324

    /**
     * Double类型的最大可能的指数值
     * System.out.println(Double.MAX_EXPONENT == Math.getExponent(Double.MAX_VALUE)); // true
     * System.out.println(Double.MAX_EXPONENT); // 1023
     * System.out.println(Math.getExponent(Double.MAX_VALUE)); // 1023
     *
     * @since 1.6
     */
    public static final int MAX_EXPONENT = 1023;

    /**
     * Double类型的最小指数值
     * System.out.println(Double.MIN_EXPONENT == Math.getExponent(Double.MIN_NORMAL)); // true
     * System.out.println(Double.MIN_EXPONENT); // -1022
     * System.out.println(Math.getExponent(Double.MIN_NORMAL)); // -1022
     *
     * @since 1.6
     */
    public static final int MIN_EXPONENT = -1022;

    /**
     * 用于表示 double值的位数。
     *
     * @since 1.5
     */
    public static final int SIZE = 64;

    /**
     * 用于表示 double值所占用的字节数。
     *
     * @since 1.8
     */
    public static final int BYTES = SIZE / Byte.SIZE;
}

3.2 方法说明

3.2.1 Double构造方法

Double的构造方法有2哥,分别是将String类型的数字转为Double类型和将双精度浮点数double数装箱为Double类型

public final class Double extends Number implements Comparable<Double> {
    public Double(String s) throws NumberFormatException {
        value = parseDouble(s);
    }
    
    public Double(double value) {
        this.value = value;
    }
}

3.2.2 valueOf方法

valueOf方法有两个,一个将String类型的数字转为Double类型的数字和将double数字装箱为Double类型。

public final class Double extends Number implements Comparable<Double> {
    public static Double valueOf(String s) throws NumberFormatException {
        return new Double(parseDouble(s));
    }
    
    public static Double valueOf(double d) {
        return new Double(d);
    }
}

3.2.3 parseDouble方法

parseDouble是将字符串类型转为双精度浮点数。valueOf与parseDouble的区别在于valueOf返回Double类型,而parseDouble返回double,valueOf在返回的时候用了构造方法。

public final class Double extends Number implements Comparable<Double> {
    public static double parseDouble(String s) throws NumberFormatException {
        return FloatingDecimal.parseDouble(s);
    }
}

3.2.4 isInfinite方法与isFinite方法

isInfinite:如果此对象表示的值是正无穷大或负无穷大,则返回 true;否则返回false。

isFinite:确定指定值是否为有限值(零、不正常或正常)。

public final class Double extends Number implements Comparable<Double> {
    public static boolean isInfinite(double v) {
        return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
    }
    public boolean isInfinite() {
        return isInfinite(value);
    }
    public static boolean isFinite(double d) {
        return Math.abs(d) <= DoubleConsts.MAX_VALUE;
    }
}
// 使用方法
public class Test {
    public static void main(String[] args) {
        if (Double.isInfinite(val) || Double.isNaN(val)){
            throw new NumberFormatException("Infinite or NaN");
        }
    }
}

3.2.5 doubleToLongBits方法

public final class Double extends Number implements Comparable<Double> {
    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;
    }
}

3.2.6 doubleToRawLongBits native方法与longBitsToDouble native方法

public final class Double extends Number implements Comparable<Double> {
    // 根据IEEE 754浮点“双格式”位布局返回指定浮点值的表示,保留非数字(NaN)值。
    public static native long doubleToRawLongBits(double value);
    
    // 返回与给定位表示相对应的 double值。
    public static native double longBitsToDouble(long bits);
}

3.2.7 compare/sum/max/min方法

  • sum方法是用来计算两个double值之和。
  • max方法是用来查找两个double值的最大值。
  • min方法是用来查找两个double值的最小值。
public final class Double extends Number implements Comparable<Double> {
    public static int compare(double d1, double d2) {
        if (d1 < d2)
            return -1;           // Neither val is NaN, thisVal is smaller
        if (d1 > d2)
            return 1;            // Neither val is NaN, thisVal is larger
        
        // Cannot use doubleToRawLongBits because of possibility of NaNs.
        long thisBits    = Double.doubleToLongBits(d1);
        long anotherBits = Double.doubleToLongBits(d2);
        
        return (thisBits == anotherBits ?  0 : // Values are equal
                (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
                        1));                          // (0.0, -0.0) or (NaN, !NaN)
    }
    public static double sum(double a, double b) {
        return a + b;
    }
    public static double max(double a, double b) {
        return Math.max(a, b);
    }
    public static double min(double a, double b) {
        return Math.min(a, b);
    }
}

4.说明

4.1 如何判断两个double类型的数字大小

1.使用Double.doubleToLongBits

Double.doubleToLongBits(0.01) == Double.doubleToLongBits(0.01)
Double.doubleToLongBits(0.02) > Double.doubleToLongBits(0.01)
Double.doubleToLongBits(0.02) < Double.doubleToLongBits(0.01)
  1. 将double数转为字符串,判断字符串是否相等

3.使用BigDecimal类型进行判断

double a = 0.001; 
double b = 0.0011; 
BigDecimal data1 = new BigDecimal(a); 
BigDecimal data2 = new BigDecimal(b); 
data1.compareTo(data2) 
非整型数,运算由于精度问题,可能会有误差,建议使用BigDecimal类型!

当此 BigDecimal 在数字上小于、等于或大于 val 时,返回 -101

4.判断是否在误差范围内

double a =...;
double b =...;
if (Math.abs(a-b) < 1E-6d) {
      ...
} 
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8