Skip to content

BigDecimal Usage Overview

Ugljesa Jovanovic edited this page May 11, 2019 · 1 revision

Floating Point

Creating

Parsing

To create a BigDecimal you can parse a string in expanded or scientific notation

Scientific

val bigDecimal = BigDecimal.parseString("1.23E-6)")
println("BigDecimal: $bigDecimal")
----- Output -----
BigDecimal: 1.23E-6

Expanded

val bigDecimal = BigDecimal.parseString("0.00000123")
println("BigDecimal: $bigDecimal")
----- Output -----
BigDecimal: 1.23E-6

From Long, Int, Short, Byte

You can convert standard types to BigDecimal, i.e. Long

val bigDecimal = BigDecimal.fromLong(7111)
println("BigDecimal: $bigDecimal")
----- Output -----
BigDecimal: 7.111E+3

Or you can specify an exponent. when you do specify an exponent, input value (long, int, short, byte) is considered to be in scientific notation.

val bigDecimal = BigDecimal.fromLongWithExponent(1, (-5).toBigInteger())
println("BigDecimal: $bigDecimal")
println("BigDecimalExpanded: ${bigDecimal.toStringExpanded()}")
----- Output -----
BigDecimal: 1.0E-5
BigDecimalExpanded: 0.00001

Extension functions

For String

val bigDecimal = "12345678.123".toBigInteger

Or for Double of Float

val bigDecimalFromFloat = 123.456f.toBigDecimal() 
val bigDecimalFromDouble = 123.456.toBigDecimal()

toString

By default toString() is returned in scientific output, but expanded output is also available

val bigDecimal = BigDecimal.parseString("123.456")
println("BigDecimal: ${bigDecimal.toStringExpanded()}")
bigDecimal.toStringExpanded() == "123.456"
----- Output -----
BigDecimal: 123.456

Arithmetic operations

Standard arithmetic operations that are present:

  • Addition
  • Subtraction
  • Multiplication
  • Division
  • Exponentiation
  • Increase by one
  • Decrease by one
  • Absolute value
  • Negate
  • Signum

(Suspiciously missing is square root, both from BigInteger and BigDecimal, should be added soon™)

Operations are executed with existing significands and then rounded down afterwards. Decimal mode parameter controls the precision and rounding mode

DecimalMode

This is a counterpart to the Java BigDecimal MathContext.

data class DecimalMode(val decimalPrecision : Long = 0, val roundingMode : RoundingMode = RoundingMode.NONE)

decimalPrecision defines how many digits should significand have

roundingMode defines rounding mode.

Decimal mode resolution
  • DecimalMode supplied to the operation always overrides all other DecimalModes set in BigDecimals

  • If a DecimalMode is set when creating a BigDecimal that mode will be used for all operations.

  • If two BigDecimals have different DecimalModes with different RoundingModes an ArithmeticException will be thrown. If the modes are same, but the precision is different, larger precision will be used.

Infinite precision

Precision 0 and roundingMode none attempt to provide infinite precisions. Exception is division, where default precision is is the sum of precisions of operands (or 6, if the sum is below 6). If result of the operation cannot fit inside precision and RoundingMode is NONE, ArithmeticException will be thrown.

Example from the tests:

   fun readmeDivisionTest() {
        assertFailsWith(ArithmeticException::class) {
            val a = 1.toBigDecimal()
            val b = 3.toBigDecimal()
            val result = a/b
        }

        assertTrue {
            val a = 1.toBigDecimal()
            val b = 3.toBigDecimal()
            val result = a.div(b, DecimalMode(20, RoundingMode.ROUND_HALF_AWAY_FROM_ZERO))
            result.toString() == "3.3333333333333333333E-1"
        }
    }

Rounding modes

Name Description
FLOOR Towards negative infinity
CEILING Towards positive infinity
AWAY_FROM_ZERO Away from zero
TOWARDS_ZERO Towards zero
NONE Infinite decimalPrecision, and beyond
ROUND_HALF_AWAY_FROM_ZERO Round towards nearest integer, using towards zero as tie breaker when significant digit being rounded is 5
ROUND_HALF_TOWARDS_ZERO Round towards nearest integer, using away from zero as tie breaker when significant digit being rounded is 5
ROUND_HALF_CEILING Round towards nearest integer, using towards infinity as tie breaker when significant digit being rounded is 5
ROUND_HALF_FLOOR Round towards nearest integer, using towards negative infinity as tie breaker when significant digit being rounded is 5