java - 为什么某些 double 在打印到控制台时会自动舍入?

标签 java double bigdecimal floating-point-precision rounding-error

假设我有以下代码:

double factor;
double num = 4.35;
BigDecimal y = new BigDecimal(num);
BigDecimal n = new BigDecimal(factor);
BigDecimal asBigDecimal = y.multiply(n);
double asDouble = num * factor;
System.out.println("Double: " + asDouble + "\tBigDecimal: " + asBigDecimal);

这就是我将 factor 设置为以下各项时发生的情况:

factor = 1:    Double: 4.35 BigDecimal: 4.3499999999999996447286321199499070644378662109375
factor = 10:   Double: 43.5 BigDecimal: 43.4999999999999964472863211994990706443786621093750
factor = 100:  Double: 434.99999999999994   BigDecimal: 434.9999999999999644728632119949907064437866210937500
factor = 1000: Double: 4350.0   BigDecimal: 4349.9999999999996447286321199499070644378662109375000

此外,当我将 System.out.print(4.35/10); 作为单独的程序运行时,我在控制台中得到 0.43499999999999994 。为什么在控制台中乘以 1、10 和 1000 会得到四舍五入的结果(作为 double )?我了解浮点精度的基础知识,并且 4.35 不应该能够以二进制形式精确表示,那么为什么 4.35 会打印到控制台(asDouble)?为什么乘以 100 或除以 10 不会自动舍入?

最佳答案

有几件事正在发生。首先,对二进制进行四舍五入,然后对十进制进行四舍五入。

查看这些 BigDecimal 值的二进制表示形式(我使用了 Decimal/Binary Converter ):

factor = 1:    100.0101100110011001100110011001100110011001100110011         (52 bits)
factor = 10:   101011.011111111111111111111111111111111111111111111111       (53 bits)
factor = 100:  110110010.11111111111111111111111111111111111111111111011     (56 bits)
factor = 1000: 1000011111101.1111111111111111111111111111111111111111100111  (59 bits)

因子 1 和 10 的结果未进行二进制舍入;它们 <= 53 位。四舍五入到小数点后 17 位以便打印,分别为 4.35 和 43.5。

因子 100 和 1000 的结果进行四舍五入。由于第 54 位为 0,因此因子 100 结果向下舍入为该值:

   factor = 100:  110110010.11111111111111111111111111111111111111111111        (53 bits)

以十进制表示,即 434.99999999999994315658113919198513031005859375。四舍五入为 17 位数字,即 434.99999999999994。

因数 1000 结果向上舍入为该值,因为第 54 位及以上的位 > 1/2 ULP:

factor = 1000: 1000011111110

即 4350。

关于java - 为什么某些 double 在打印到控制台时会自动舍入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26089408/

相关文章:

java - 禁用 JTextField 中的字母

java - 方法中的继承程序错误

swift - 添加字典 swift 3 中包含的 double

java - 如何在 Lucene 3.0.1 中索引 BigDecimal 值

java - 价格值中的 BigDecimal 舍入 : doubleValue() vs setScale(2, BigDecimal.ROUND_HALF_UP)

java - 使用 Java BigDecimal 表示 15 精度数字(小数位数为 2)

java - 如何在启动 Android 应用程序时启动特定 fragment

Java 流 "forEach"但不消耗流

c - 将字符串转换为 double 后返回值不正确?

swift - 如何在 Swift 中找到 Double 和 Float 的最大值