I’m working on calculator project but when I tried to use two similar ways of comparing double and int numbers I got different results. So my question is Why are these ways of comparing works differently?
//some code that parse the string
//...
//code of calculating:
fun calculateIn(queueNumbers: Queue<Double>, queueActions: Queue<Char>) {
var action: Char
var result = queueNumbers.poll()
var operand: Double
while (!queueNumbers.isEmpty()) {
operand = queueNumbers.poll()
action = queueActions.poll()
when (action) {
'-' -> result -= operand
'+' -> result += operand
'*' -> result *= operand
'/' -> result /= operand
'%' -> result = result % operand * -1.0
}
}
var pointNum = 8.3
println("pointNum = " + pointNum)
println(if(pointNum.compareTo(pointNum.toInt()) == 0) pointNum.toInt() else pointNum)
println("result = " + result)
println(if(result.compareTo(result.toInt()) == 0) result.toInt() else result)
}
The problem is that doubles and ints are fundamentally different types. If you call toInt() on a Double this will loose data (drop the decimal places).
It is “better” to compare as doubles. To make things worse, however, when comparing doubles for equality you generally should do a comparison in a given precision (as floating point math introduces errors). If you want precision, you use BigDecimal instead, this type has “unlimited” precision and will not loose precision, but can lead to large numbers.
I generally agree with what @pdvrieze said, but still, this looks like a bug in the compiler to me.
Minimal reproducible example:
fun test1(): Int {
val d: Double?
d = 8.3
return d.compareTo(8) // 0
}
fun test2(): Int {
val d: Double
d = 8.3
return d.compareTo(8) // 1
}
Technical difference between these two code samples is that the value is boxed in test1() and unboxed in test2(). If we look at the generated bytecode for test2(), everything looks as expected: