【问题标题】:Why are certain doubles automatically rounded when printed to the console?为什么某些双精度数在打印到控制台时会自动舍入?
【发布时间】:2014-09-28 20:37:02
【问题描述】:

假设我有以下代码:

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 会给出四舍五入的答案(作为双精度数)?我了解浮点精度的基础知识,并且 4.35 不应该能够以二进制形式精确表示,那么为什么 4.35 打印到控制台(asDouble)?为什么乘以 100 或除以 10 不自动四舍五入?

【问题讨论】:

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


【解决方案1】:

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

查看那些 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 的结果不是以二进制四舍五入的;它们是

因子 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。

【讨论】:

  • 将此标记为答案,但有一个问题:第 54 位(及以后)有什么特别之处?我以为只有 52 位用于存储双精度数的小数部分。
  • @Kootling 52 位被显式存储,但有一个隐式前导 1 位
  • 那 1 位是干什么用的?另外,这是否意味着舍入发生在第 54 位?意思是,如果第 54 位为 1,则该数字将向上取整,如果为 0,则将向下取整?
  • @Kootling 1 只是数字的一部分。数字是标准化的,这意味着第一位始终为 1,因此无需存储它。 (有关详细信息,请查看 IEEE 格式。)关于第 54 位:是的,如果为 0,则向下舍入,如果为 1,则向上舍入,并且还有另外 1 位(意味着它超过了一半)。还有一种情况,第 54 位为 1,超出的所有位均为 0,表示中途情况,如果第 53 位为 1,则向上取整,如果第 53 位为 0,则向下取整。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-13
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多