How do I get exact decimals (BigDecimal) in EK9?

← Advanced Type System · Ref: Q1367

Float is 64-bit binary floating point, so it cannot represent values like 0.1 exactly (0.1 + 0.2 is not quite 0.3). When you need EXACT decimals, use BigDecimal - arbitrary-precision decimal arithmetic. (For currency specifically, use Money.)

EXACT ARITHMETIC

  sum <- BigDecimal("0.1") + BigDecimal("0.2")   // exactly 0.3

+, -, * and ^ are exact. Create from a String (exact), an Integer, or a Float.

EQUALITY IS BY VALUE, NOT SCALE

Unlike java.math.BigDecimal.equals, EK9 compares by value: 1.0 equals 1.00. ==, <=> and #? all use value comparison, so equal values also hash the same.

DIVISION AND SQRT

A non-terminating quotient like 1/3 needs a bound, so division and sqrt keep 34 significant digits (MathContext DECIMAL128). Division by zero is UNSET.

ROUNDING

  rounded <- BigDecimal("3.14159").round(2)      // 3.14 (HALF_UP)

DISPLAY

$ gives the plain-string form (no scientific notation).

Like BigInteger, BigDecimal has no #^ promote operator. See Q1366 for BigInteger and Q23 for the Money type. Use 'ek9 -h BigDecimal' for the full API.

Example

defines module qa.bigdecimal.usage

  defines program

    BigDecimalUsage()
      stdout <- Stdout()

      //Exact: 0.1 + 0.2 is exactly 0.3 (Float cannot do this).
      sum <- BigDecimal("0.1") + BigDecimal("0.2")
      stdout.println(`sum: ${sum}`)

      //Equality is by value, not scale: 1.0 equals 1.00.
      a <- BigDecimal("1.0")
      b <- BigDecimal("1.00")
      equal <- a == b
      stdout.println(`1.0 == 1.00: ${equal}`)

      //Round to a number of decimal places.
      rounded <- BigDecimal("3.14159").round(2)
      stdout.println(`rounded: ${rounded}`)
Other ways to ask this
  • Why is 0.1 + 0.2 not 0.3 with Float?
  • How do I do high-precision decimal arithmetic?
  • What do I use for exact decimals that are not money?

Coming from another language?

Java: java.math.BigDecimal - but equals is scale-sensitive (1.0 != 1.00); EK9 compares by value. Python: decimal.Decimal. Go: shopspring/decimal or math/big Rat. Rust: rust_decimal. EK9: BigDecimal is built in; exact (0.1+0.2==0.3); value equality (1.0==1.00); DECIMAL128 division; round(places); no #^ promote. Use Money for currency.

Keywords: value, bigdecimal, scale, precision, rounding, arithmetic, exact, money, equality, 0.1, 0.3, float, decimal