Im trying to create a program for the collatz conjecture, and I need it to work for bigger numbers. So, i tried to use the BigInteger class, but it seems to run into an error with the two types: bigint and int.
I've looked up the problems for big int, and it seemingly works with the addition and multiplication. However, when trying to get the remainder when dividing by two, it returns an error. (At the start of runtime).
import java.math.BigInteger;
import java.math.Bigdecimal;
import java.util.Objects;
import java.util.Scanner;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
boolean repeat = true;
while (repeat){
int i = 0;
Scanner intIn = new Scanner(System.in);
Scanner strIn = new Scanner(System.in);
System.out.println("Enter number you want solved, Don't type 0. Use this program with caution");
BigInteger num = intIn.nextBigInteger();
while (num.equals(new BigInteger("1")) == false){
if (num.equals(new BigInteger("1"))){
// The issue currently is that the remainder function returns an error, but im not sure exactly what is wrong with it.
} else if (num.remainder(new BigInteger("2")) == 0) {
num = num.divide(new BigInteger("2"));
} else {
num = num.multiply(new BigInteger("3"));
num = num.add(new BigInteger("1"));
}
i += 1;
}
System.out.println("It took " + i + " steps to reach 1. Would you like to do another number? (yes/no)");
String yn = strIn.nextLine();
if (Objects.equals(yn, "no")){
repeat = false;
}
}
}
}
In line 21, the error is with the remainder function. (in case you missed the comment)
The problem is that num.remainder(new BigInteger("2"))
returns another BigInteger
and you try to compare that BigInteger
with an int value (0).
The Java Language Specification 15.21. Equality Operators states:
The equality operators may be used to compare two operands that are convertible (§5.1.8) to numeric type, or two operands of type boolean or Boolean, or two operands that are each of either reference type or the null type. All other cases result in a compile-time error.
(There is an additional constraint for equality operators on reference types, see the last block).
Since BigInteger
is a reference type that is not convertible to a numeric type (5.1.8. Unboxing Conversion mentions that only Byte
, Short
, Character
, Integer
, Long
, Float
and Double
are) the last clause (all other cases result in a compile-time error) applies.
To fix it change the comparison to
num.remainder(new BigInteger("2")).equals(BigInteger.ZERO)
Note that the BigInteger
class has some helpful constants for your code:
BigInteger.ZERO
BigInteger.ONE
BigInteger.TWO
Your loop makes repeated use of these values and therefore will run faster if you use these constants instead of repeatedly creating new BigInteger
objects for them.
IMHO you should even consider creating another local constant for the value three:
BigInteger THREE = BigInteger.valueOf(3);
and use it for example in
num.multiply(THREE)
One more note:
num.equals(new BigInteger("1")) == false
looks weird and can be written shorter as
!num.equals(BigInteger.ONE)
One last note (already mentioned in the comments):
Use only one Scanner
for all the input. Using two scanners might seem to work in your simple case, but will fail in others (for example when using input redirection).
Using only one scanner can lead to other problems as can be seen in Scanner is skipping nextLine() after using next() or nextFoo()?, but it is still the correct way to do.
There is an additional condition for equality comparison of reference types mentioned in 15.21.3. Reference Equality Operators == and !=
It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values are null).