Operations and performance of BigDecimal and BigInteger
In this section we look in a little more detail at some of the most important
methods on BigDecimal and BigInteger,
including an analysis of their performance.
As a general note, it is worth bearing in mind that a BigDecimal is
essentially a wrapper around a BigInteger that "remembers where the
decimal point is". Because of the way we are used to dealing with
numbers, as humans, we may have to "think a bit more" when calculating with
non-integers by hand compared to integers (e.g. we may have learnt the
7 times table by heart to speed up certain calculations,
but probably not the .7 times table).
But to a computer implementation, it is essentially no more effort
to manipulate non-integers than it is integers, and so on the whole,
methods on BigDecimal
tend to perform similarly to analogous methods on BigInteger.
add() and subtract()
Both BigInteger and BigDecimal have add() and
subtract() methods that take as parameters another instance of the same class.
The main thing to remember when using these methods is that, as with all of the
arithmetic methods in general, a new instance is returned:
public BigInteger add(BigInteger[] numbers) {
BigInteger total = new BigInteger(0);
for (BigInteger n : numbers) {
total = total.add(n);
}
return total;
}
If you need to add a different type for some reason (e.g. adding a primitive int
to a BigInteger, or adding a BigInteger to a BigDecimal),
then you need to wrap the argument in the relevant type.
In terms of performance, these methods scale linearly as a function of the number
of digits in the (larger) number being added.
multiply()
The multiply() method works in a similar way to the add() and
subtract() method, creating a new instance of the relevant class that
is the product of the number it is called on and that passed in as an argument.
Unlike addition and subtraction, the time required to perform a multiplication
scales exponentially with the number of digits in the multiplicands: or more
specifically, multiplying a number with n digits by a number with m
digits takes in the order of nm time. Or put another way, doubling the number
of digits of the numbers multiplied together means that the time taken will
increase fourfold.
This performance behaviour comes from the standard JDK implementation, which
uses a "naive" algorithm of cycling through every combination of digits to perform
the multiplication, much as you would if calculating by hand. If you require faster
multiplication of very large numbers (greater than a few thousand digits), then
it is faster to implment a more sophisticated algorithm. On the next page, we
look at the performance
of the multiply() method and of a simple implementation of
the more scalable Karatsuba's method.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.