Four Common Pitfalls of The Bigdecimal Class and How To Avoid Them
Four Common Pitfalls of The Bigdecimal Class and How To Avoid Them
Menu
x=0.10000000000000000555111512312578270211815
y=0.1
BigDecimal x = BigDecimal.valueOf(1.012345678
BigDecimal y = new BigDecimal("1.012345678901
System.out.println("x=" + x);
System.out.println("y=" + y);
x=1.0123456789012346
y=1.01234567890123456789
Here, the x value has lost four decimal digits because a double
has a precision of only 15–17 digits (a float has a precision of
only 6–9 digits), while a BigDecimal is of arbitrary precision
(limited only by memory).
False
System.out.println(x.compareTo(y) == 0);
True
x=12000
scale=-3
The method doesn’t round the fractional part, but it does round
the unscaled value to the given number of significant digits
(counting from left to right), leaving the decimal point untouched,
which results, in the example above, of a negative scale of -3.
But what about the scale? Why is it -3 and not 0, as you would
expect for a value of 12000?
x=12345.68
c=289570111.3153564320
d=289570111.32
The total number of digits to the left of the decimal point can be
calculated like this:
bigDecimal.precision() - bigDecimal.scale() +
where
e=289570111.32
c.setScale(2, RoundingMode.HALF_UP);
it’s obvious which one you would choose to ensure readable and
concise code.
First, I need a name for the new class; I’m going use “Decimal.”
The Decimal class is going to extend BigDecimal and, thus, it
inherits all public fields and methods from its superclass.
@Override
public Decimal add(BigDecimal augend) {
return new Decimal(super.add(augend));
}
Below, I’m going to add only those constructors that make sense
from a business logic perspective and that will avoid most of the
issues discussed above.
Double constructors
I’m aware that the new double constructor may lead to issues
due to a double’s limited precision. Nevertheless, I must admit
that I personally prefer the double constructor to the String
constructor, because it feels more natural to write numbers as
what they are, namely as numbers and not as strings. It is also
less error-prone because the numbers you enter are recognized
as numbers by the compiler.
I’ll give you an example for this: Most countries in Europe use a
comma instead of a period as a decimal separator, which could
lead to the following error at runtime:
However, if you still think the use of the double constructor is too
risky, just omit it and use the String constructor instead. That
way, you are sure to avoid both pitfalls #1 and #2.
Now that I have added constructors, I’m going to add some new
methods to make it easier to compare two decimal numbers.
The recommended way to compare two instances of
BigDecimal is to use the compareTo() method, for example:
• a.equalTo(b)
• a.greaterOrEqualTo(b)
• a.lessOrEqualTo(b)
• a.greaterThan(b)
• a.lessThan(b)
I believe that anyone reading code that uses these new methods
will immediately understand the methods correctly. Note that the
equalTo() method should help to avoid pitfall #3.
int scale();
RoundingMode mode();
AMOUNT(2, RoundingMode.HALF_UP),
RATE(6, RoundingMode.HALF_UP),
SURFACE(4, RoundingMode.HALF_UP);
private final int scale;
@Override
public int scale() {
return scale;
}
@Override
public RoundingMode mode() {
return mode;
}
c=289570111.32
Note that the new rounding method should help to avoid pitfall
#4.
String pattern();
Locale locale();
}
public enum Format implements FormatInfo {
@Override
public String pattern() {
return pattern;
}
@Override
public Locale locale() {
return locale;
}
c=289,570,111.32
A real-world example
Now that you are able to address the four pitfalls discussed
above and also do some basic formatting operations on the new
class, let’s see how this all works together in a real-world
example.
assertTrue(amount.equalTo(new Decimal(16_977.
System.out.println("amount=" + amount.format(
amount=16,977.70
assertTrue(amount.compareTo(new BigDecimal("1
System.out.println("amount=" + formatter.form
amount=16,977.70
Dig deeper
Class BigDecimal
Uses of Class java.math.BigDecimal
How BigDecimal extends Number
“Records come to Java”
Frank Kiwy
Frank Kiwy is a senior software developer
and project leader who works for a
government IT center in Europe. His focus
is on Java SE, Java EE, and web
technologies. Kiwy is also interested in
software architecture and is committed to
continuous integration and delivery. He is
currently involved in implementing the
European Union¿s Common Agricultural
Policy, where he's in charge of several
projects. When programming, he values
well-designed software with clear and easy-
to-understand APIs.
FacebookTwitter LinkedIn Email