内部如何运作?
即使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 :(得分: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 Standard和IEEE 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