Can someone explain me why the result of this code...
# announcements
z
Can someone explain me why the result of this code is false? Why
log(243.0, 3.0)
returns 4.999999999999999 😮
d
Floating point numbers 😉 https://softwareengineering.stackexchange.com/a/101170 Or, a little more light-hearted:

https://www.youtube.com/watch?v=PZRI1IfStY0

👍 2
You probably want a decimal type, which on the JVM can be done using
BigDecimal
z
Didn’t expect precision problems with such simple example 😕
d
You have the same thing in decimal. 1/3 + 1/3 + 1/3 = 1, but if you have limited precision then you get 0.33333 + 0.33333 + 0.33333 = 0.99999
The same thing is happening here, but in binary and with floating point numbers
z
I see, thanks for clarification 🙂 Will dig into it a little bit more
m
On JVM, the safest way to deal with non-integers is BigDecimal. If you don't care about rounding errors, then feel free to use float/double, but if you care about precision, BigDecimal is the way to go. In Kotlin, use the
toBigDecimal()
extension, and it will always 'do the right thing'. One major gotcha with the Java BigDecimal is using anything other than the String constructor. If you pass a double/float, then it uses that internally for computations, and you STILL get rounding errors. The Kotlin extension ensures the BigDecimal constructed does the right thing.
m
Wow @Mike TIL
m
Yes, BigDecimal is a huge gotcha waiting to happen. I have no idea why it was implemented that way, but I've been working with Java a long time, so have seen it happen... Hence the use
toBigDecimal()
in Kotlin always recommendation. There are some minor exceptions, as BigDecimal has a few common numbers available as constants (ZERO, ONE, TEN), so use those. The other 'gotcha' with BigDecimal is precision and scale. If you create
BigDecimal("10", 2)
and `BigDecimal("`0", 3)`, and then compare them using
equals
, it will be false. That's because the
equals
compares scale, too, so the first number is 10.00 and the second is 10.000, so they're obviously not the same ;)
j
You should never use == to compare doubles or floats. One option is to use an epsilon value in your comparison, but that can still fail if numbers are really big or really small. e.g. 10^-24 is probably the same as 10^-26 for you (both pretty close to 0) but they are off by a factor of 100. There is a ton of literature about this stuff. More surprisingly, some numbers have more than one representation, meaning that even when the numbers are for all intents and purposes the same value, the == operation will return false.
m
I agree regarding primitives. The problem is devs don't think of BigDecimal as an effective primitive, so they automatically use
equals
, and assumes it will do the right thing. For BigDecimal, us programmers tend to think of 10.0 and 10.00 being equal, or don't even think about this, so it's a common error when using BigDecimal. Substitute
==
for
equals
when using Kotlin.
j
Hmmm.. I thought == delegates to equals in Kotlin and you need to use === to check if the references are equal