Java中double类型异常行为解析及五类核心疑问
Java double类型浮点数的疑问解答
测试代码
public void myTestMethod() { double num; double factor; double compared; double result1; double result2; String output; num = 0.3; factor = 10; compared = 3; //num * 10 result1 = num * factor; //add 10 num, which is mathematically equal to num * 10 result2 = num + num + num + num + num + num + num + num + num + num; output = "num: " + num + "\n"; output = output + "result1: " + result1 + "\n"; output = output + "result2: " + result2 + "\n"; if (result1 == compared) { output = output + "result1 == compared\n"; } else { output = output + "result1 != compared\n"; } if (result2 == compared) { output = output + "result2 == compared\n"; } else { output = output + "result2 != compared\n"; } System.out.print(output); }
运行输出
num: 0.3 result1: 3.0 result2: 2.9999999999999996 result1 == compared result2 != compared
问题解答
1. num的取值是否精确等于0.3?
不等于。0.3的十进制无法转化为有限长度的二进制小数,double类型(遵循IEEE 754标准)存储的是0.3的近似值,而非精确值。
2. 若num是0.3,为何result2 == compared的结果为false?
num本身不是精确的0.3,每次相加都会累积微小的误差。10次相加后,误差被放大,最终结果和精确值3之间的差距超出了double能忽略的范围,因此相等判断不成立。
3. 若num不是0.3,为何其字符串输出为"0.3"?我了解二进制浮点数总能被十进制精确表示,若num不是0.3,输出应类似"0.300000000001"。
Java在将double转为字符串时,会遵循最短十进制表示规则:它会输出最短的十进制数,这个数在转换回double时能得到原有的二进制值。实际存储的近似值和0.3的差距极小,最短的十进制表示刚好是"0.3",而非更长的带尾差的字符串。
4. 若num不是0.3,为何result1 == compared的结果为true?
num的近似值乘以10后,得到的结果刚好被double精确表示为3.0。IEEE 754的舍入规则使得这个乘法操作的结果恰好落在了精确值3的二进制表示上,因此相等判断成立。
5. 若num不是0.3,其实际值是什么?
num的实际值是最接近0.3的IEEE 754双精度浮点数,具体为十六进制表示的0x1.3333333333333p-2,对应的十进制精确值是0.299999999999999988897769753748434595763683319091796875。
内容的提问来源于stack exchange,提问作者zhoudu
相关产品推荐
相关产品推荐

