Search code examples
javamathbigintegercollatz

How to fix incompatible operand with BigInteger and int


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)


Solution

  • 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).