I am performing a simple multiplication with BigDecimal and I have found some strange behaviour when multiplying by zero (multiplying by zero is correct in this use-case).
Basic maths tells me that anything multiplied by zero will equal zero (see:Zero Product Property and Multiplication Properties)
However, the following code will consistently fail with the same error:
assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0)));
java.lang.AssertionError: Expected :0 Actual :0E-48
Is this an inaccuracy with BigDecimal or is there some niche branch of maths that I'm missing somewhere?
Notes: JDK 1.6.0_27 running in IntelliJ 11
Use the multiply() method to multiply one BigDecimal to another in Java. This method returns a BigDecimal whose value is (this × multiplicand), and whose scale is (this. scale() + multiplicand.
A BigDecimal is an exact way of representing numbers. A Double has a certain precision. Working with doubles of various magnitudes (say d1=1000.0 and d2=0.001 ) could result in the 0.001 being dropped alltogether when summing as the difference in magnitude is so large. With BigDecimal this would not happen.
The value of the BigDecimal is (BigInteger/10**scale). A negative scale will result in a NumberFormatException.
You can't use the equals()
method to compare BigDecimals
, like this assertion does. That is because this equals function will compare the scale. If the scale is different, equals()
will return false, even if they are the same number mathematically.
You can however use compareTo()
to do what you want:
As @assylias points out, you should also use the new BigDecimal("22.3")
constructor to avoid double precision issues.
BigDecimal expected = BigDecimal.ZERO; BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO); assertEquals(0, expected.compareTo(actual));
There is also a method called signum()
, that returns -1, 0 or 1 for negative, zero, and positive. So you can also test for zero with
assertEquals(0, actual.signum());
There are 2 issues with your code:
new BigDecimal("22.3")
instead of the double constructor new BigDecimal(22.3)
to avoid double precision issuesIn other words, the following code (which correctly uses compareTo) still returns false:
BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10)); System.out.println(bd.compareTo(BigDecimal.ONE) == 0);
because 0.1d * 10d != 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With