Kotlin compiler apparently losing Double value precision

Why is it that the Kotlin compiler transforms this here:
val someDouble:Double=0.8 - 0.2
to
double someDouble = 0.6000000000000001D;
I have experiented a bit with other combinations of the two literals that get subtracted, but couldn’t figure out any clear pattern.

This is nothing to do with Kotlin; it’s a consequence of how floating-point numbers work.

Floating-point numbers are stored as binary fractions. And the binary fraction for 0.2 does not terminate: it’s 0.001100110011001100110011… So there’s no way to store it exactly in a finite space, however much precision you use.

Similarly, 0.8 is 0.110011001100110011001100… in binary. In fact, almost no decimal fractions have exact representations in binary floating-point.

Computers try to work around this as best they can: when displaying floating-point numbers, they usually try to pick the nearest decimal number. In simple cases, this hides the problem. But sooner or later, it bites you.

So, if you need to store decimal fractions exactly, don’t use floating-point! Floating-point numbers are great if you need fast results and/or a huge range but don’t care about 100% accuracy. And in many cases a factor of about 1 in 10^8 or 10^16 isn’t significant. But when it is, use something else! (In particular, never use floating-point to store money values, and be very careful when testing them for equality or using them as loop counters.)

The Java BigDecimal class is usually the best alternative: it stores numbers using decimal fractions, with as much precision as you need. It’s slower and takes more memory than floating-point, but it has been optimised pretty well.

Depending on your exact needs, you might get away with using integers, integer pairs, or even strings. But if you want exact answers, don’t use floating-point!

2 Likes

This phenomenon of floating point arithmetic is called 0.1 + 0.2 == 0.30000000000000004.

Thanks a lot. I sort of suspected that there is not really a problem with the compiler but rather with my personal computer science skills level. :slight_smile:

fun main() {
var precision = 0.0.toBigDecimal()
precision = precision + 5.6.toBigDecimal()
precision = precision + 5.8.toBigDecimal()
println(precision)
}

output : 11.4