4

I needed to check if a BigDecimal instance is a multiple of another BigDecimal instance. Since I am restricted to Java 1.4, I couldn't make use of BigDecimal.remainder(...).

I came up with the following code:

/**
 * Returns <code>true</code> if <code>multiple</code> is a multiple of <code>base</code>.
 *
 * @param multiple
 * @param base
 * @return
 */
public static boolean isMultipleOf(final BigDecimal multiple, final BigDecimal base)
{
    if (multiple.compareTo(base) == 0)
        return true;

    try
    {
        multiple.divide(base, 0, BigDecimal.ROUND_UNNECESSARY);
        return true;
    }
    catch(ArithmeticException e)
    {
        return false;
    }
}

The code assumes that rounding is unnecessary only if the quotient of multiple divided by base is an integer. Is this assumption correct?

Edit
Incorporated the hint by Lando to explicitly set the scale of the quotient to 0. Otherwise the following call would have wrongly returned true:

isMultipleOf(new BigDecimal("10.25"), new BigDecimal("5"));

Edit
Wrote a JUnit test and found out I have to take care of the special case where both multiple and base are 0. So I added a test for equality to the code above.

bassim
  • 886
  • 1
  • 21
  • 33
  • 1
    May be look at Java 1.6 or so source, that gives you what you want exactly right? – kosa Sep 03 '12 at 15:24
  • Its worth noting that Java 6 is soon to be End Of Free Support so if you do upgrade, I suggest going straight to Java 7. ;) – Peter Lawrey Sep 03 '12 at 15:34
  • Nambari, that's what I did. However, as it is with good design, high level functionality is implemented via specificly parameterized calls to multi-purpose low-level functionality (mostly private methods here). I would be ending up copying the whole class. Take a look: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/math/BigDecimal.java#BigDecimal – bassim Sep 03 '12 at 15:59
  • 1
    @PeterLawrey: The decision if and when to upgrade is not mine :( The code must be executable on our customers application server (an SAP NetWeaver WebAS 7.0) which only supports Java 1.4. – bassim Sep 03 '12 at 16:47

2 Answers2

2

The javadoc says...

Throws: ArithmeticException - if divisor==0, or roundingMode==ROUND_UNNECESSARY and this.scale() is insufficient to represent the result of the division exactly.

So the assumption seems correct that an ArithmeticException will occur if the scale() is not sufficient; i.e. remainder is non-zero.

Bharat Sinha
  • 13,973
  • 6
  • 39
  • 63
  • `System.out.println(isMultipleOf(new BigDecimal("125"), new BigDecimal("10")));` returns `false`. The scale is different for 1.25 the scale is 2 and for 125 scale is 0. – Bharat Sinha Sep 03 '12 at 15:38
2

you should use this instead:

multiple.divide(base, 0, BigDecimal.ROUND_UNNECESSARY);

Because if you don't pass the zero it will apply the scale of the dividend (unless you are completely sure that the scale of that will always be zero in which case why are you not using a BigInteger instead?)

ArithmeticException - val==0, or roundingMode==ROUND_UNNECESSARY and this.scale() is insufficient to represent the result of the division exactly

Source

Frank Orellana
  • 1,820
  • 1
  • 22
  • 29