Java 中的 double 是一个遵循 IEEE 754 标准的64位双精度浮点数,它的取值范围不是连续的,因为它需要用一部分位来表示指数(决定数量级),一部分位来表示尾数(决定精度)。

- 正数最大值: 约
7976931348623157 x 10^308 - 正数最小值(非零): 约
9406564584124654 x 10^-324 - 负数最小值: 约
-1.7976931348623157 x 10^308 - 负数最大值(非零): 约
-4.9406564584124654 x 10^-324
double 的内部结构(IEEE 754 标准)
要理解它的取值范围,必须先了解它的64位是如何分配的:
| 部分 | 占用位数 | 作用 | 解释 |
|---|---|---|---|
| 符号位 (Sign) | 1 位 | 决定正负 | 0 代表正数,1 代表负数。 |
| 指数位 (Exponent) | 11 位 | 决定数量级 | 决定了这个数有多大或多小。 |
| 尾数位 / 有效数 (Mantissa / Significand) | 52 位 | 决定精度 | 决定了这个数的具体数值。 |
一个 double 值的计算公式为:
值 = (-1)^符号位 * (1 + 尾数) * 2^(指数 - 偏移量)
- 偏移量: 指数是11位的无符号整数,范围是 0 到 2047,为了能表示负指数(即小数),标准规定了一个偏移量 1023,实际的指数是
指数位 - 1023。 - 尾数: 尾数部分总是以 开头(这是隐含的,不占用存储空间),所以实际的尾数是
1 + 尾数位,这提供了52位+1位(隐含)的有效数字。
取值范围的推导
基于上述结构,我们可以推导出关键值。
a. 最大值
要得到最大值,我们需要:

- 符号位:
0(正数) - 指数位: 全部为
1,即2047,这是指数能表示的最大值。 - 尾数位: 全部为
1,为了获得最大的精度。
计算:
- 实际指数 =
2047 - 1023 = 1024 - 实际尾数 =
1 + (所有尾数位都为1),这是一个非常接近2的数,但小于2。
最大值 ≈ (1 + 尾数最大值) * 2^1024。
在 Java 中,这个值被定义为 Double.MAX_VALUE。
b. 最小正值 (正数中最小的非零值)
要得到最小的正数,我们需要:
- 符号位:
0(正数) - 指数位: 全部为
0,即0,这是指数能表示的最小值。 - 尾数位: 全部为
0,为了获得最小的精度。
计算:
- 实际指数 =
0 - 1023 = -1023 - 实际尾数 =
1 + 0 = 1
最小正值 = 1 * 2^(-1023)。
在 Java 中,这个值被定义为 Double.MIN_VALUE。注意:这是最小的非零正值,而不是绝对值最小的 double。
c. 绝对值最小的 double (可表示的最小数)
这比 Double.MIN_VALUE 还要小,我们需要:
- 符号位:
0(正数) - 指数位: 全部为
0,即0。 - 尾数位: 最后一位为
1,其余为0。
计算:
- 实际指数 =
0 - 1023 = -1023 - 实际尾数 =
1 + 2^(-52)(因为只有最后一位是1)
绝对值最小的 double = (1 + 2^(-52)) * 2^(-1023)。
这个值非常接近 Double.MIN_VALUE,但比它略大。
d. 特殊值:无穷大 和 NaN
当指数位全为 1 (即 2047) 时,表示的不是普通数字,而是特殊值:
-
无穷大: 如果尾数位全为
0。Double.POSITIVE_INFINITY(符号位为0)Double.NEGATIVE_INFINITY(符号位为1)- 当一个计算结果超出
Double.MAX_VALUE时,就会得到无穷大。0 / 0.0。
-
非数字: 如果尾数位不全为
0。Double.NaN(Not a Number)- 表示一个未定义或无法表示的值。
0 / 0.0或Math.sqrt(-1.0)。
Java 代码中的表示与验证
你可以直接在 Java 代码中获取这些常量,并验证它们。
public class DoubleRange {
public static void main(String[] args) {
// 1. 最大值
double max = Double.MAX_VALUE;
System.out.println("最大值 (MAX_VALUE): " + max);
System.out.println("科学计数法表示: " + String.format("%.16e", max));
// 2. 最小正值 (最小的非零正数)
double minPositive = Double.MIN_VALUE;
System.out.println("\n最小正值 (MIN_VALUE): " + minPositive);
System.out.println("科学计数法表示: " + String.format("%.16e", minPositive));
// 3. 比较MIN_VALUE和绝对值最小的double
double smallestNonZero = Math.ulp(minPositive); // ulp函数返回最小有效位上的值
System.out.println("\n绝对值最小的double (ulp of MIN_VALUE): " + smallestNonZero);
System.out.println("科学计数法表示: " + String.format("%.16e", smallestNonZero));
// 4. 特殊值:无穷大
double infinity = Double.POSITIVE_INFINITY;
System.out.println("\n正无穷大 (POSITIVE_INFINITY): " + infinity);
System.out.println("1.0 / 0.0 的结果: " + (1.0 / 0.0));
// 5. 特殊值:NaN
double nan = Double.NaN;
System.out.println("\n非数字 (NaN): " + nan);
System.out.println("0.0 / 0.0 的结果: " + (0.0 / 0.0));
// 注意:NaN与任何值(包括它自己)比较都为false
System.out.println("nan == nan 的结果: " + (nan == nan)); // false
System.out.println("使用Double.isNaN(nan): " + Double.isNaN(nan)); // 正确的判断方式
}
}
运行结果:
最大值 (MAX_VALUE): 1.7976931348623157E308
科学计数法表示: 1.7976931348623157e+308
最小正值 (MIN_VALUE): 4.9E-324
科学计数法表示: 4.9406564584124654e-324
绝对值最小的double (ulp of MIN_VALUE): 4.9406564584124654e-324
科学计数法表示: 4.9406564584124654e-324
正无穷大 (POSITIVE_INFINITY): Infinity
1.0 / 0.0 的结果: Infinity
非数字 (NaN): NaN
0.0 / 0.0 的结果: NaN
nan == nan 的结果: false
使用Double.isNaN(nan): true
(注意:MIN_VALUE 的输出 9E-324 是简化的,更精确的值是 9406564584124654 x 10^-324)
重要注意事项
-
精度问题:
double提供的范围是以牺牲精度为代价的,它只能精确表示某些特定的二进制小数,很多十进制小数(如1)在double中都是近似值,这就是为什么1 + 0.2的结果不精确等于3的原因。System.out.println(0.1 + 0.2); // 输出 0.30000000000000004
-
比较浮点数: 由于精度问题,永远不要使用 来比较两个
double是否相等,应该判断它们的差值是否在一个很小的误差范围内(epsilon)。// 错误的方式 if (d1 == d2) { ... } // 正确的方式 if (Math.abs(d1 - d2) < 1E-9) { ... } -
选择
double还是float:double(64位): 默认选择,范围更大,精度更高,在现代计算机上性能通常与float相当,是绝大多数情况下的首选。float(32位): 仅在内存极度受限的情况下(如大量数据存储、Android 开发)使用,它的范围和精度都远小于double。
总结表格
| 常量 | 描述 | 值 (近似) | 科学计数法 (近似) |
|---|---|---|---|
Double.MAX_VALUE |
可表示的最大的 double 值 |
7976931348623157 x 10^308 |
7976931348623157e+308 |
Double.MIN_VALUE |
可表示的最小非零 double 值 |
9406564584124654 x 10^-324 |
9406564584124654e-324 |
Double.POSITIVE_INFINITY |
正无穷大 | Infinity |
- |
Double.NEGATIVE_INFINITY |
负无穷大 | -Infinity |
- |
Double.NaN |
非数字 | NaN |
- |
