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.
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.
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.
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.
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.
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.
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
- Create from strings: Write
new BigDecimal("19.99"), notnew BigDecimal(19.99d). - Set scale and rounding together: Pass both to
setScaleanddivide. - Compare with compareTo: Use
compareToor==rather thanequalswhen scale may vary. - Store money as decimals: Keep exact values in your data and round only for display.
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
List all Groovy tutorials.