0
\$\begingroup\$

I wrote a method that multiplies two integers. Is there a faster approach that doesn't use the * operator?

The method mult(a, b) multiplies two arbitrary integers. Is there a quicker way to multiply two numbers, without using * in java?

static int mult(int a, int b) {
 if (a > b)
 return recMult(a, b);
 return recMult(b, a);
}
static int recMult(int max, int min) {
 if (min <= 1)
 return min == 1 ? max : 0;
 int cntOfMin = 0, i = 1;
 while ((i = i << 1) <= min)
 cntOfMin++;
 return (max << cntOfMin) + recMult(max, min - (1 << cntOfMin));
}

This method doesn't work on negative numbers and doesn't handle overflows.

AJNeufeld
35.2k5 gold badges41 silver badges103 bronze badges
asked Jul 26, 2022 at 21:04
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Your heuristic is not optimal. recMult is using binary arithmetic to multiply two numbers. It recurses a number of times based on the number of 1-bits in the second number. You pass in the smaller of the two numbers as the second number, but there is no guarantee the smaller number has fewer 1-bits.

Consider 8 * 7, or in binary, 1000 * 111. The 7 is the smaller number, so you use it as the second argument, and you compute (8 << 2) + (8 << 1) + (8 << 0) + 0. If you had chosen to 8 as the second argument, you would have computed (7 << 3) + 0 ... far fewer operations.

The function Integer.bitCount(int i) returns the number of 1-bits in an integer. Using this, we could rewrite mult(int a, int b) as follows:

static int mult(int a, int b) {
 if (Integer.bitCount(a) > Integer.bitCount(b))
 return recMult(a, b);
 return recMult(b, a);
}

The result should be faster.

Similarly, Java provides several functions in the Integer class which can directly extract the 1-bits found in an integer. These are .lowestOneBit(i), .highestOneBit(i), .numberOfLeadingZeros(i), and .numberOfTrailingZeros(i). The last function is most useful here, as the number of trailing zeros corresponds to the bit position of the least significant 1-bit. For example, 8, or 1000 has 3 trailing zeros, and (1 << 3) == 8.

Using this to simplify rectMult(), we could get something like:

private static int recMult(int multiplicand, int multiplier) {
 int product = 0;
 while (multiplier != 0) {
 int shift = Integer.numberTrailingZeros(multiplier);
 product += multiplicand << shift;
 multiplier -= 1 << shift;
 }
 return product;
}

Since the second number is no longer guaranteed to be the smaller of the two, I've renamed max and min to multiplicand and multiplier.

I've also replaced the recursion with a simple loop, which should additionally speed things up.

Additionally, I've declared this helper function private, since it is unlikely other classes will use it.

answered Jul 27, 2022 at 4:19
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.