Search code examples
kotlinextension-methodsbigdecimal

How do I use the extension functions for BigDecimal in kotlin?


As I understand it, Kotlin has operator overloading for BigDecimal instances. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/java.math.-big-decimal/

Why can't I actually use it in my program ? Is there some special import I need to do to get this working ? I couldn't understand why it chose to round up to 0.2.

import java.math.BigDecimal

fun main() {
    val num = BigDecimal("15.5")
    val den = BigDecimal("100")
    
    val operatorDivide = num/den
    println("Operators- 15.5/100 is: $operatorDivide") // 0.2
    
    val fnDivide = num.divide(den)
    println("Functions- 15.5/100 is: $fnDivide") // 0.155
    
    val fnDiv = num.div(den)
    println("Operator fun ? 15.5/100 is: $fnDiv") // 0.2
}

https://pl.kotl.in/TB_wmF95N


Solution

  • div (aka /) is implemented as

    public inline operator fun BigDecimal.div(other: BigDecimal): BigDecimal = 
        this.divide(other, RoundingMode.HALF_EVEN)
    

    This calls divide(BigDecimal,RoundingMode), which does something different from the divide(BigDecimal) overload that you are calling in your code.

    divide(BigDecimal,RoundingMode) keeps the scale of this:

    Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().

    but divide(BigDecimal) only specifies what the preferred scale is.

    Returns a BigDecimal whose value is (this / divisor), and whose preferred scale is (this.scale() - divisor.scale())

    The preferred scale doesn't have to be strictly followed by division - at the top of the JavaDocs page, just below the table showing the preferred scales for each operation, it says:

    These 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.

    The "scale" of a BigDecimal created using BigDecimal(String) constructor is basically "how many decimal places it has" - 15.5 has scale 1, and 100 has scale 0.

    div maintains the scale of the result as 1, so the result is rounded to 0.2. 0.155 would need a scale of at least 3 to represent. divide(BigDecimal) sets the preferred scale to 1, too, but since the exact result can be represented with a scale of 3, the result of divide has scale 3.