【问题标题】:Android: java rounding error. Can't understand why?Android:java 舍入错误。不明白为什么?
【发布时间】:2013-03-19 02:51:43
【问题描述】:

谁能解释为什么地球上这些“相同”的表达式会返回不同的值?

(new BigDecimal(String.valueOf(131.7d))).multiply(new BigDecimal(String.valueOf(0.95d))).doubleValue() = 125.115

(new BigDecimal(               131.7d )).multiply(new BigDecimal(               0.95d )).doubleValue() = 125.11499999999998

BigDecimal 在它们之间有什么不同?

【问题讨论】:

  • 对于那些投票结束重复的问题,问题相似但不重复。

标签: java android bigdecimal rounding


【解决方案1】:

如果你看API documentation

BigDecimal(double val)
          Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value.

对比

BigDecimal(String val)
          Translates the string representation of a BigDecimal into a BigDecimal.

这些其实不是一回事。在double 构造函数中,它使用浮点数(本质上是不准确的)。在String 构造函数中,它采用您提供的确切值并且 进行浮点转换。所以这实际上意味着上面的构造函数不是“相同”的表达式

【讨论】:

  • 那么,除了在将值传递给 BigDecimal 之前将值转换为字符串之外,没有其他方法可以获取此计算的“正确”值 (131.7 * 0.95 = 125.115)?这对我来说太奇怪了!
  • 我不明白为什么 2 个具有相同输入值的构造函数会返回 2 个不同的结果。如果 Double.valueOf(String.valueOf(131.7d)) == 131.7d,为什么 BigDecimal 返回不同的值?这对我来说没有任何意义!
  • 嗯,您实际上并没有在这里回答 Christian 的问题,因为他在这两种情况下都以 131.7d 和 0.95d 开头。他观察到差异的原因不是因为不同的 BigDecimal 构造函数,而是 String.valueOf(dobule) 在转换为字符串之前间接舍入了参数,而不是返回具有参数确切值的字符串。
【解决方案2】:

如果您阅读 API 文档,您会发现 String.valueOf(dobule) 使用 Double.toString(double) 来格式化值。这可能并不明显,但 Double.toString(double) 在将其格式化为字符串之前会将其四舍五入:

m 或 a 的小数部分必须打印多少位? 必须至少有一位数字来表示小数部分,并且 超出此数量,但仅与所需数量一样多,更多的数字 唯一地将参数值与类型的相邻值区分开来 双倍的。也就是说,假设 x 是精确的数学值 由这种方法产生的十进制表示表示 一个有限的非零参数 d。那么 d 必须是最接近的双精度值 到 x;或者如果两个双精度值同样接近 x,则 d 必须是 其中之一和 d 的有效位的最低有效位必须 为 0。

这样做的结果是String.valueOf(131.7d) 将返回字符串“131.7”,即使参数的确切值是 131.699999999999998863131622783839702606201171875。原因是小数部分不能总是用二进制小数精确表示(与浮点数和双精度数一起使用)。

因此,新的new BigDecimal(String.valueOf(131.7)) 将创建一个精确值为 131.7 的 BigDecimal。 new BigDecimal(131.7) 将创建一个精确值为 131.69999999999998863131622783839702606201171875 的 BigDecimal。

【讨论】:

    猜你喜欢
    • 2013-04-15
    • 1970-01-01
    • 2011-10-07
    • 2020-06-15
    • 2023-04-10
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多