ionspin / kotlin-multiplatform-bignum

A Kotlin multiplatform library for arbitrary precision arithmetics
Apache License 2.0
364 stars 42 forks source link

BigDecimal.divideAndRemainder throws an exception when the exponent is -1 #195

Closed theisenp closed 2 years ago

theisenp commented 2 years ago

Describe the bug Calling BigDecimal.divideAndRemainder throws an exception when the exponent is -1 and no explicit DecimalMode has been provided.

To Reproduce This statement:

0.1.toBigDecimal().divideAndRemainder(BigDecimal.ONE)

Throws an exception with a stacktrace like this:

kotlin.ArithmeticException: Rounding mode with 0 digits precision.
    at kotlin.Throwable#<init>(/opt/buildAgent/work/c5a36d4d82b914cf/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:24)
    at kotlin.Exception#<init>(/opt/buildAgent/work/c5a36d4d82b914cf/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23)
    at kotlin.RuntimeException#<init>(/opt/buildAgent/work/c5a36d4d82b914cf/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34)
    at kotlin.ArithmeticException#<init>(/opt/buildAgent/work/c5a36d4d82b914cf/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:119)
    at com.ionspin.kotlin.bignum.decimal.DecimalMode#<init>(/Users/ptheisen/Development/kotlin-multiplatform-bignum/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/decimal/DecimalMode.kt:97)
    at com.ionspin.kotlin.bignum.decimal.DecimalMode#<init>(/Users/ptheisen/Development/kotlin-multiplatform-bignum/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/decimal/DecimalMode.kt:86)
    at com.ionspin.kotlin.bignum.decimal.BigDecimal#divideAndRemainder(/Users/ptheisen/Development/kotlin-multiplatform-bignum/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/decimal/BigDecimal.kt:1334)

Expected behavior No exception, correct division/remainder result.

Platform

Additional context The method creates a default decimal mode if none has been set on the dividend:

val resolvedRoundingMode = this.decimalMode ?: DecimalMode(exponent + 1, RoundingMode.FLOOR)

So when the exponent is -1, the precision resolves to 0, which is reserved for unlimited precision and can't be paired with RoundingMode.FLOOR.

divideAndRemainder is the root cause, but many other methods use it to compute their results and so are also affected (e.g. remainder, isWholeNumber, etc).

ionspin commented 2 years ago

Thanks for reporting and for providing additional context, it helps a lot!

ionspin commented 2 years ago

@theisenp fix should be available in an half an hour or so when CI/CD finishes the build. It will be in snapshot version 0.3.4-SNAPSHOT. Once again, thanks for reporting!

theisenp commented 2 years ago

Awesome, thanks for the quick fix!