ZetCode

Groovy BigDecimal and BigInteger

last modified October 15, 2026

Binary floating-point numbers such as double cannot represent many decimal values exactly, which causes errors in money calculations and other exact arithmetic. Groovy has two classes for exact results: BigDecimal for decimal values and BigInteger for integers of any size. This tutorial shows how to use both, control rounding, and avoid common pitfalls.

Floating-Point Errors

With double values, 0.1 + 0.2 is not exactly 0.3. Groovy's decimal literals, such as 0.1, are BigDecimal by default, so the same sum is exact. The suffix d forces a double.

FloatingPointError.groovy
println 0.1d + 0.2d
println 0.1d + 0.2d == 0.3d

println 0.1 + 0.2
println 0.1 + 0.2 == 0.3

The double sum prints 0.30000000000000004, so the comparison fails. The BigDecimal sum is exactly 0.3.

Creating BigDecimal Values

Create a BigDecimal from a string to keep the exact decimal value. Creating one from a double carries over the binary error, so avoid that form for money.

CreateBigDecimal.groovy
import java.math.BigDecimal

def exact = new BigDecimal("19.99")
def fromDouble = new BigDecimal(19.99d)

println exact
println fromDouble
println exact.scale()

exact prints 19.99. fromDouble prints a long expansion of the binary value, showing why strings are the safe way to create decimals.

Arithmetic and Scale

Addition, subtraction, and multiplication keep the exact value. The scale is the number of digits after the decimal point. Division needs an explicit scale and rounding mode, because the result may not terminate.

Arithmetic.groovy
import java.math.BigDecimal
import java.math.RoundingMode

def price = new BigDecimal("19.99")
def quantity = new BigDecimal("3")

println price * quantity
println((price * quantity).setScale(2, RoundingMode.HALF_UP))

def share = new BigDecimal("100").divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP)
println share

Multiplying 19.99 by 3 gives 59.97 exactly. divide needs a scale of 2 and a rounding mode, so 100 / 3 rounds to 33.33. Without these arguments, a non-terminating division throws an ArithmeticException.

Rounding Modes

RoundingMode sets how the last kept digit is chosen. HALF_UP is the everyday choice for money, and HALF_EVEN is the banker's rounding used in many financial reports.

RoundingModes.groovy
import java.math.BigDecimal
import java.math.RoundingMode

def values = ["2.45", "2.55", "2.65", "2.75"]

values.each { v ->
    def d = new BigDecimal(v)
    println "$v HALF_UP=${d.setScale(1, RoundingMode.HALF_UP)} HALF_EVEN=${d.setScale(1, RoundingMode.HALF_EVEN)}"
}

The modes differ only when the discarded digit is exactly 5. HALF_UP always rounds up, so 2.45 becomes 2.5. HALF_EVEN rounds to the even neighbour, so 2.45 becomes 2.4 and 2.65 becomes 2.6. Values such as 2.55 round the same way in both modes because the kept digit is already even.

Comparing BigDecimal Values

equals considers scale, so 2.0 and 2.00 are not equal under equals. Use compareTo or the == operator, which compares numeric value.

CompareBigDecimal.groovy
import java.math.BigDecimal

def a = new BigDecimal("2.0")
def b = new BigDecimal("2.00")

println a.equals(b)
println a.compareTo(b) == 0
println a == b

The equals call returns false because the scales differ. compareTo and == both return true, since they compare the numeric value.

BigInteger for Large Integers

BigInteger holds integers of any size. Groovy's G suffix creates one from a literal, and the ** operator computes powers.

BigIntegerExample.groovy
import java.math.BigInteger

def big = 2G ** 100
println big

def factorial = { n -> (1..n).inject(1G) { acc, i -> acc * i } }
println factorial(30)

println new BigInteger("123456789012345678901234567890").mod(new BigInteger("97"))

2G ** 100 is far beyond the range of long, yet it is exact. The factorial of 30 is computed with BigInteger arithmetic through inject, which would overflow a long.

Best Practices

Source

Java BigDecimal API | Java BigInteger API

Use BigDecimal wherever exact decimal results matter, and BigInteger for integers beyond the long range. Set the scale and rounding mode explicitly, and avoid building decimals from double values.

Author

My name is Jan Bodnar, and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Groovy tutorials.