【问题标题】:Why is 0.29999999999999998 converted to 0.3?为什么 0.29999999999999998 转换为 0.3?
【发布时间】:2016-03-08 23:31:45
【问题描述】:

它在内部是如何工作的?

它如何决定将0.29999999999999998 转换为0.3,即使0.3 不能用二进制表示?

这里还有一些例子:

scala> 0.29999999999999998
res1: Double = 0.3

scala> 0.29999999999999997
res2: Double = 0.3

scala> 0.29999999999999996
res3: Double = 0.29999999999999993

scala> 0.29999999999999995
res4: Double = 0.29999999999999993

【问题讨论】:

  • 我访问了链接并了解为什么 0.3 表示为 0.2999999.. 但它没有解释机器如何将 0.2999999.. 转换为 0.3? (例如,它是否有存储在某处的映射表?)

标签: scala floating-point precision


【解决方案1】:

涉及两个转换。

第一个 0.29999999999999998 转换为 0.299999999999999988897769753748434595763683319091796875,即最接近的可表示数字。

接下来,将 0.299999999999999988897769753748434595763683319091796875 转换为十进制以进行打印。 0.3 也是转换为 0.2999999999999999988897769753748434595763683319091796875 的数字之一,它是被打印出来的数字,因为它太短了。

每个有限双精度数都可以精确地表示为小数。通常,默认输出不会尝试打印确切的值,因为它可能很长 - 远远长于上面的示例。一个常见的选择是打印将在输入时转换为双精度的最短小数部分。两种转换都是使用非平​​凡算法完成的。有关输出算法的一些讨论和参考,请参阅Algorithm to convert an IEEE 754 double to a string?

================================================ ===============

在 cmets 中有一些关于值 0.30000000000000004 的讨论。我同意 Rick Regan 和 Jesper 的 cmets,但认为添加到这个答案中可能会有用。

最接近 0.30000000000000004 的双精度值的确切值为 0.3000000000000000444089209850062616169452667236328125。 [0.30000000000000000166533453693773481063544750213623046875, 0.30000000000000000721644966006351751275360584259033203125] 范围内的所有十进制数转换为0.3000000000000000 超出范围,因此它没有足够的位数。 0.30000000000000004 在范围内,因此不需要更多的数字来正确识别双精度数。

【讨论】:

  • 为什么不简单地打印最接近的可表示数字而不是打印 0.3?另外,它是如何从 0.299999999999999988897769753748434595763683319091796875 到 0.3 的?它使用什么机制?谢谢!
  • 只是为了确保我理解正确 -- 0.300000000000000044408920985006 是机器存储的 --- 但是机器总是输出 0.300000000000000004 因为算法,对吧?
  • 你能指出我为什么选择 17 个小数位作为输出格式吗?
  • @Tanin 因为double 是 64 位 IEEE 754 format,其精度约为 16 位十进制数字。研究一下浮点数在计算机上的工作原理(点击链接)。
  • @Tanin 这里有一个地方你可以读到为什么 17 是“幻数”(我今年早些时候写的一篇文章):exploringbinary.com/…
【解决方案2】:

注意在 Scala 中 Double(参见 IEEE 754 StandardIEEE Floating-Point Arithmetic),原始声明值向上舍入到最接近的值,

val x = 0.29999999999999998
x: Double = 0.3

"0.29999999999999998".toDouble
Double = 0.3

一样
0.2999999999999999999999999999999999999999999999999999999999998
Double = 0.3

同样在BigDecimal中对于任意精度的十进制浮点表示(见API),Double类型的原始值(构造函数的参数)首先被四舍五入,即

BigDecimal(0.29999999999999998) == 0.3
Boolean = true

BigDecimal(0.29999999999999998)
scala.math.BigDecimal = 0.3

但是,原始值的文本声明不会被解释为Double,因此会向上取整,

BigDecimal("0.29999999999999998") == 0.3
Boolean = false

即,

BigDecimal("0.29999999999999998")
scala.math.BigDecimal = 0.29999999999999998

【讨论】:

    猜你喜欢
    • 2015-04-25
    • 2016-05-09
    • 2016-05-13
    • 2012-01-26
    • 2011-10-16
    • 2014-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多