为什么Long.MaxValue适合Double但< Long.MaxValue没有

时间:2015-02-25 23:30:50

标签: scala

我知道这有一个简单的答案,但令我感到困惑。

为什么Long.MaxValue可以存储在Double中并以longValue形式返回,但较小的Long会丢失精度。

我原本预计在53位之后会失去精度?这里发生了什么

scala> val x:Double = Long.MaxValue  // x: Double = 9.223372036854776E18    (9223372036854775807)
scala> x == Long.MaxValue            // Boolean = true
scala> x.longValue == Long.MaxValue  // Boolean = true
scala> val y = 1234567890123456789L  // y: Long = 1234567890123456789  // less than Long.MaxValue
scala> y < x                         // Boolean = true
scala> val z:Double = y              // z: Double = 1.23456789012345677E18
scala> z == y                        // Boolean = true
scala> z.longValue == y              // Boolean = false  // why ? MaxValue fits in the Double
scala> z.longValue                   // 1234567890123456768 <-- loss of 21

2 个答案:

答案 0 :(得分:5)

这不是&#34;拟合&#34;。双打只是inherently inexact。一些值将被准确表示,一些值不会被表示。看起来你找到了一个可以(你的x)和一个可以(y)。

您选择的价值观并不特别。这里有类似的行为,其中较小的值明显适合&#34;成双打:

val a = 1.1        // a: Double = 1.1
a == 1.1           // true

val b = 2.2        // b: Double = 2.2
b == 2.2           // true

val c = 1.1 + 2.2  // c: Double = 3.3000000000000003
c == 3.3           // false

答案 1 :(得分:2)

实际上不是拟合,而 会失去精确度。

但是损失是因为它被围捕了:

scala> BigDecimal.exact(Long.MaxValue.toDouble)
res0: scala.math.BigDecimal = 9223372036854775808

scala> Long.MaxValue
res1: Long = 9223372036854775807

当您尝试将过大的Double放入Long时会发生什么?

scala> 1e100.toLong
res2: Long = 9223372036854775807

它被截断了。

所以Long.MaxValue向上舍入为2^63,可以用53位和二进制指数精确表示,因为它大于Long.MaxValue,它会变回Long.MaxValue当你转换为Long时。