Jim Clermonts
Jim Clermonts

Reputation: 2660

Rounding error down when not adding a round number using RoundingMode HALF_UP in Kotlin

consider below method:

fun main() {
    var costs = 0
    var transactionFee = 1.325

    var total = (costs + transactionFee).toRoundedUpDouble()
}

fun Double.toRoundedUpDouble(fraction: Int = 2) =
    BigDecimal(this).setScale(fraction, RoundingMode.HALF_UP).toDouble()

I want a number with 2 decimal after the comma, rounded up from 5. e.g. 1.325 becomes 1.33. This works when I add a round number, but not when I don't:

Output:

5.00 + 1.325 becomes 6.33 = good
5 + 1.325 becomes 6.33 = good
1 + 1.325 becomes 2.33 = good

1.325 becomes 1.32 = NOT GOOD
0 + 1.325 becomes 1.32 = NOT GOOD 
0.00 + 1.325 becomes 1.32 = NOT GOOD 
0.000 + 1.325 becomes 1.32 = NOT GOOD 

This thread doesn't answer my question.

Upvotes: 1

Views: 106

Answers (1)

Joffrey
Joffrey

Reputation: 37749

You say that this thread doesn't answer your question, but I it really does.

As mentioned in that thread, double literals lie to you, and println as well. To know the actual value that these literals give you, you can use BigDecimal this way:

println(BigDecimal(1.325))     // 1.3249999999999999555910790149937383830547332763671875
println(BigDecimal(0 + 1.325)) // 1.3249999999999999555910790149937383830547332763671875
println(BigDecimal(5 + 1.325)) // 6.32500000000000017763568394002504646778106689453125

If you want accurate results, use BigDecimal from the start, and make sure to initialize them with strings, not double literals:

fun main() {
    var costs = BigDecimal.ZERO
    var transactionFee = BigDecimal("1.325")

    var total = (costs + transactionFee).roundedUp()
    println(total) // 1.33
    println(total.toDouble()) // 1.33
}

fun BigDecimal.roundedUp(fraction: Int = 2) = setScale(fraction, RoundingMode.HALF_UP)

Upvotes: 4

Related Questions