I know there is a simple answer for this but it has me puzzled.
Why is it that Long.MaxValue can be stored in a Double and returned as longValue, but a lesser Long loses precision.
I would have expected a loss of precision after 53 bits ? What is going on here
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
It's not a matter of "fitting". Doubles are just inherently inexact. Some values will be represented exactly, some won't. It looks like you found one that can be (your x
) and one that can't (y
).
It's not particular to the values you've chosen. Here's similar behavior with smaller values that clearly "fit" into Doubles:
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
It's actually not fitting, and it is losing precision.
But the loss is because it's being rounded up:
scala> BigDecimal.exact(Long.MaxValue.toDouble)
res0: scala.math.BigDecimal = 9223372036854775808
scala> Long.MaxValue
res1: Long = 9223372036854775807
What happens when you try to fit a too-big Double
into a Long
?
scala> 1e100.toLong
res2: Long = 9223372036854775807
It's truncated.
So Long.MaxValue
is rounded up to 2^63
which can be represented exactly with 53 bits and a binary exponent, and since it's bigger than Long.MaxValue
it turns back into Long.MaxValue
when you convert to Long
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With