> ### Solution for
> Programming Exercise 9.2

> THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

> Exercise 9.2: As discussed in Section 1, values of type `int` are limited to 32 bits. Integers that are too large to be represented in 32 bits cannot be stored in an `int` variable. Java has a standard class, `java.math.BigInteger`, that addresses this problem. An object of type `BigInteger` is an integer that can be arbitrarily large. (The maximum size is limited only by the amount of memory on your computer.) Since `BigIntegers` are objects, they must be manipulated using instance methods from the `BigInteger` class. For example, you can't add two `BigIntegers` with the `+` operator. Instead, if `N` and `M` are variables that refer to `BigIntegers`, you can compute the sum of `N` and `M` with the function call `N.add(M)`. The value returned by this function is a new `BigInteger` object that is equal to the sum of `N` and `M`.

> The `BigInteger` class has a constructor `new BigInteger(str)`, where `str` is a string. The string must represent an integer, such as "3" or "39849823783783283733". If the string does not represent a legal integer, then the constructor throws a `NumberFormatException`.

> There are many instance methods in the `BigInteger` class. Here are a few that you will find useful for this exercise. Assume that `N` and `M` are variables of type `BigInteger`.

> > `N.add(M)` -- a function that returns a `BigInteger` representing the sum of `N` and `M`.

> > `N.multiply(M)` -- a function that returns a `BigInteger` representing the result of multiplying `N` times `M`.

> > `N.divide(M)` -- a function that returns a `BigInteger` representing the result of dividing `N` by `M`.

> > `N.signum()` -- a function that returns an ordinary `int`. The returned value represents the sign of the integer `N`. The returned value is 1 if `N` is greater than zero. It is -1 if `N` is less than zero. And it is 0 if `N` is zero.

> > `N.equals(M)` -- a function that returns a `boolean` value that is `true` if `N` and `M` have the same integer value.

> > `N.toString()` -- a function that returns a `String` representing the value of `N`.

> > `N.testBit(k)` -- a function that returns a `boolean` value. The parameter `k` is an integer. The return value is `true` if the `k`-th bit in `N` is 1, and it is `false` if the `k`-th bit is 0. Bits are numbered from right to left, starting with 0. Testing "`if (N.testBit(0))`" is an easy way to check whether `N` is even or odd. `N.testBit(0)` is `true` if and only if `N` is an odd number.

> For this exercise, you should write a program that prints `3N+1` sequences with starting values specified by the user. In this version of the program, you should use `BigIntegers` to represent the terms in the sequence. You can read the user's input into a `String` with the `TextIO.getln()` function. Use the input value to create the `BigInteger` object that represents the starting point of the `3N+1` sequence. Don't forget to catch and handle the `NumberFormatException` that will occur if the user's input is not a legal integer! You should also check that the input number is greater than zero.

> If the user's input is legal, print out the `3N+1` sequence. Count the number of terms in the sequence, and print the count at the end of the sequence. Exit the program when the user inputs an empty line.

> Discussion

> My solution uses a subroutine, `printThreeNSequence(N)`, to print out the `3N+1` sequence starting from the `BigInteger`, `N`. The subroutine assumes that `N` is not `null` and that it represents a value that is greater than one. (These conditions are ensured by the main program which calls the subroutine.) Given these assumptions, the subroutine cannot generate any errors. The only interesting aspect of the subroutine is that all operations on `N` must be performed using instance methods from the `BigInteger` class. For example, to multiply `N` by 2, I use a statement "`N = N.multiply(TWO);`", where `TWO` is a `BigInteger` that represents the integer 2. My program defines `TWO` as a constant, along with several other `BigIntegers` that represent values that I need:

>            static final BigInteger THREE = new BigInteger("3");
>            static final BigInteger ONE = new BigInteger("1");
>            static final BigInteger TWO = new BigInteger("2");

> With these constants, the code for computing the next term in a `3N+1` sequence becomes:

>            if (N.testBit(0) == false) {
>                    // N is even.  Divide N by 2.
>                N = N.divide(TWO);
>            }
>            else {
>                    // N is odd.  Multiply N by 3, then add 1.
>                N = N.multiply(THREE);
>                N = N.add(ONE);
>            }

> You can find the complete subroutine in the solution that is given below.

> In the `main()` routine, the user's input is read into a variable, `line`, of type `String`. The input is used to construct a `BigInteger` with the statement "`N = new BigInteger(line);`". Since this statement can produce a `NumberFormatException`, it is placed in a `try` statement that can catch and handle the error. The test "`if (N.signum() == 1)`" is used to make sure that `N >= 1`. The value of `N.signum()` is 1 if and only if `N` is a positive integer. Here is the loop form the `main()` routine that processes the users input:

>           while (true) {
>              TextIO.putln();
>              TextIO.putln("Enter the starting value, or press return to end.");
>              TextIO.put("? ");
>              line = TextIO.getln().trim();
>              if (line.length() == 0)
>                  break;
>              try {
>                  N = new BigInteger(line);
>                  if (N.signum() == 1)
>                     printThreeNSequence(N);
>                  else
>                     TextIO.putln("Error:  The starting value cannot be less than or equal to zero.");
>              }
>              catch (NumberFormatException e) {
>                  TextIO.putln("Error:  \"" + line + "\" is not a legal integer.");
>              }
>           }

> The Solution

>         /*
>             This program prints out 3N+1 sequences for starting values of N that
>             are entered by the user.  Since integers are represented as objects of
>             type BigInteger, it will work for arbitrarily large integers.  The
>             starting value specified by the user must be greater than zero.  The
>             program continues to read input from the user and print 3N+1 sequences
>             until the user inputs an empty line.  If the user's input is illegal,
>             the program will print an error message and continue.
>         */

>         import java.math.BigInteger;

>         public class BigThreeN {

>            static final BigInteger THREE = new BigInteger("3");
>            static final BigInteger ONE = new BigInteger("1");
>            static final BigInteger TWO = new BigInteger("2");

>            public static void main(String[] args) {

>               String line;   // A line of input from the user.
>               BigInteger N;  // The starting point for the 3N+1 sequence,
>                              //   as specified by the user.

>               TextIO.putln("This program will print 3N+1 sequences for positive starting values");
>               TextIO.putln("that you enter.  There is no pre-set limit on the number of");
>               TextIO.putln("digits in the numbers that you enter.  The program will end when");
>               TextIO.putln("you enter an empty line.");

>               while (true) {
>                  TextIO.putln();
>                  TextIO.putln("Enter the starting value, or press return to end.");
>                  TextIO.put("? ");
>                  line = TextIO.getln().trim();
>                  if (line.length() == 0)
>                      break;
>                  try {
>                      N = new BigInteger(line);
>                      if (N.signum() == 1)
>                         printThreeNSequence(N);
>                      else
>                         TextIO.putln("Error:  The starting value cannot be less than or equal to zero.");
>                  }
>                  catch (NumberFormatException e) {
>                      TextIO.putln("Error:  \"" + line + "\" is not a legal integer.");
>                  }
>               }

>               TextIO.putln();
>               TextIO.putln("OK.  Bye for now!");

>            }  // end main()

>            static void printThreeNSequence(BigInteger N) {
>                  // Print the 3N+1 sequence starting from N, and count the number
>                  // of terms in the sequence.  It is assumed that N is not null and
>                  // that it is greater than zero.

>               int count;  // The number of terms in the sequence.

>               TextIO.putln();
>               TextIO.putln("The 3N+1 sequence starting with " + N + " is:");
>               TextIO.putln();

>               TextIO.putln(N.toString());   // Print N as the first term of the sequence
>               count = 1;

>               while ( ! N.equals(ONE) ){   // Compute and print the next term
>                  if (N.testBit(0) == false) {
>                          // N is even.  Divide N by 2.
>                      N = N.divide(TWO);
>                  }
>                  else {
>                          // N is odd.  Multiply N by 3, then add 1.
>                      N = N.multiply(THREE);
>                      N = N.add(ONE);
>                  }
>                  TextIO.putln(N.toString());
>                  count++;
>               }

>               TextIO.putln();
>               TextIO.putln("There were " + count + " terms in the sequence.");

>            }  // end printThreeNSequence

>         } // end BigThreeN

> [ Exercises | Chapter Index | Main Index ]