为什么0.29999999999999998转换为0.3?

时间:2015-12-04 05:26:37

标签: scala floating-point precision

内部如何运作?

即使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

2 个答案:

答案 0 :(得分:10)

涉及两次转换。

首先将0.29999999999999998转换为0.299999999999999988897769753748434595763683319091796875,最近的可表示数字。

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

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

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

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

最接近的两倍于0.30000000000000004的确切值是0.3000000000000000444089209850062616169452667236328125。范围[0.3000000000000000166533453693773481063544750213623046875,0.3000000000000000721644966006351751275360584259033203125]中的所有十进制数都会转换为该值,并且即使在该范围之外也没有数字这样做。 0.3000000000000000超出范围,因此没有足够的数字。 0.30000000000000004在范围内,因此无需更多数字即可正确识别双精度数。

答案 1 :(得分:1)

请注意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的原始值(构造函数的参数)首先被舍入,即< / p>

BigDecimal(0.29999999999999998) == 0.3
Boolean = true

BigDecimal(0.29999999999999998)
scala.math.BigDecimal = 0.3

然而,原始值的 textual 声明不会被解释为Double,因此被舍入,

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

即,

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