0

I have the following code:

import java.math.RoundingMode
fun fValueNettoBase(priceNetto:Double , quantity:Double) = dRound(priceNetto * quantity, 2)
fun dRound(double: Double, nrOfDec: Int = 2): Double =
    double.toBigDecimal().setScale(nrOfDec, RoundingMode.HALF_UP).toDouble()
fun main() {
    val quantity = 1.38
    val price = 3.25
    println("${fValueNettoBase(price,quantity)}")
}

it is rounded incorrectly to 4.48 instead of 4.49, any ideas why? My gut feel is it has to do with the conversion from double to big decimal and the other way round, but I'm not sure how to make it work

Stachu
  • 1,614
  • 1
  • 5
  • 17
  • 4
    The problem isn't BigDecimal, the problem is floating point operations aren't exact. 1.38 * 3.25 in double is closer to 4.484999999999999 than 4.485, when you then convert to BigDecimal and round with HALF_UP, that becomes 4.48. You need to use BigDecimal all the way (and then construct the big decimals with strings, not doubles). – Mark Rotteveel Apr 13 '23 at 07:49
  • @MarkRotteveel Strictly speaking, they _are_ exact — but they're exact in _binary_ floating-point. And since almost all decimal fractions can't be represented as (finite) binary fractions, that means converting between decimal fractions and float/double types will almost always involve some approximation. To underline what's been said many times: **Never use float/double if you care about exact decimal values!** And in particular, **Never ever store money values in float/double!** – gidds Apr 13 '23 at 18:43

1 Answers1

3

If you want this rounding to work correctly, you must never, ever use Double. You must use BigDecimal at every stage of your code. Using Double can introduce a small +/- to your values that can cause rounding to go in a different direction than you expect.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413