JVM源码解读-Double类
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表示负 | 1bit | 63 |
exponent | 指数部分 | 11bit | 52-62 |
fraction | 小数部分 | 52bit | 0-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)
- 将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 时,返回 -1、0 或 1。
4.判断是否在误差范围内
double a =...;
double b =...;
if (Math.abs(a-b) < 1E-6d) {
...
}