Weird BigDecimal math

Hi, I think “/” implementation in stdlib can create very subtle bugs, like this:

val v1 = BigDecimal( “0.007”) / BigDecimal( “2”)
val v2 = BigDecimal( “0.007”).divide(BigDecimal( “2”))
println(“v1=$v1 v2=$v2”)

Produces this:
v1=0.004 v2=0.0035

1 Like

It seems like rounding is mode is passed when using operator call and a final result depends on scaling and precision:

// expected: 0.25
println("1/4 = ${1.toBigDecimal() / 4.BigDecimal()}") // prints: 0
println("1.0/4 = ${BigDecimal("1.0") / 4.toBigDecimal()}") // prints: 0.2
println("1.00/4 = ${BigDecimal("1.00") / 4.toBigDecimal()}") // prints: 0.25

From the documentation of the operator div extension:

The scale of the result is the same as the scale of this (divident), and for rounding the RoundingMode.HALF_EVEN rounding mode is used.

The documentation for the divide(BigDecimal divisor) method, however, states the following:

Returns a BigDecimal whose value is (this / divisor) , and whose preferred scale is (this.scale() - divisor.scale()) ; if the exact quotient cannot be represented (because it has a non-terminating decimal expansion) an ArithmeticException is thrown.

The key point here is that the latter only mentions the preferred scale. The documentation has the following to say about preferred scales:

These (the preferred, ed.) scales are the ones used by the methods which return exact arithmetic results; except that an exact divide may have to use a larger scale since the exact result may have more digits. For example, 1/32 is 0.03125.