My assignment is write a method that reduces a BigInteger using recursion. If the number is even, split it in half then repeat the process, if the number is odd, then multiply it by 3, add 1, and repeat the process, while keeping track of the number of times this happens.
The recursion continues until the number reaches 1, then I return the amount of times this process has occurred.
I think my methods should work fine. They don't. They reduce the BigInteger to 1, then it begins looping upwards to a random number. I don't understand why. Any help would be appreciated.
EDIT: What I mean by 'looping upwards': After the big int is reduced to 1, the method continues 'looping' and every time it loops, the number grows, also the counter diminishes as the method loops. There's nothing in the method to account for that so I don't know why it does it. That explanation doesn't really help, but I put SystemPrintLn's everywhere and saw it do it.
public int Problem9(BigInteger value) {
BigInteger zero = BigInteger.valueOf(0);
BigInteger one = BigInteger.valueOf(1);
BigInteger two = BigInteger.valueOf(2);
BigInteger three = BigInteger.valueOf(3);
int count = reduceBigInt(value, zero, one, two, three, 1);
return count;
}
public int reduceBigInt(BigInteger num, BigInteger zero,
BigInteger one, BigInteger two, BigInteger three, int i) {
if (num.equals(one))
return i;
else if ((num.remainder(two)) == zero)
reduceBigInt((num.divide(two)), zero, one, two, three, i++);
else
reduceBigInt((num.multiply(three).add(one)), zero, one, two, three, i++);
return i;
}
There are a few issues:
The argument
i++will pass the original value ofi(before increment), which means that every recursive call will receive the same value for their locali, which is 1. When the recursive call comes back, the next statement will doreturn i, when at that timeihas been incremented once (remember it is a local variable), and so thatreturnwill always return 2.Although the recursive calls return a value, this value is ignored by the caller making the recursive call.
== zerois not the way to compare BigIntegers. In this particular case, you could use thetestBitmethod instead.As you start out with
iequal to 1, your function could never return 0, yet when the input is 1 the response should be 0.It is a pity you have to pass
zero,one,twoandthreeover and over again as argument, consuming stack space. Instead, define them as fields. You can even get rid of all of them:equals(one)you can usebitLength()as only 1 has a bit length of 1.mod(two)and compare withzero, usetestBit(0)divide(two), useshiftRight(1)multiply(three), simply addnumto itself twice, and to add the one we can do that after the first addition by flipping the least bit (which is guaranteed to be zero as we just doubled the number).If you decide to use recursion, then it is more elegant to not pass
ias argument, but to have each recursive call execute as if it was the top-level execution -- without needing information of what was already counted before. In that approach, the base case should return 0, and the caller should add one to the returned value from recursion.Here is how you could do that: