CSCI A201/A597

Lecture Notes 5

Spring 2000


In which we look at what it takes to solve Homework One.

First I hope that this set of notes will show you that programming is as easy as planning a trip.

Second, I hope it will provide you with enough practice to become well versed in control structures in Java, such as if statements, and while, and for loops.

When we're done you should be just about ready to code everything in and turn it by the end of lab later this week as your Homework One assignment.

The 3x + 1 Function

The homework assignment revolves around a function (let's call it f) which is defined on the set of strictly positive integers (>= 1, that is) in the following way:

int f(int x) {
  if (x % 2 == 0) { return 2 * x;     } 
  else            { return 3 * x + 1; } 
} 
Yes, this is new syntax for you, but it doesn't hurt to be exposed to something new each time. This is the way in which we define methods in Java. We're not going to use this today in any actual program, other than to define the function f as a function that takes odd numbers into 3 times the number plus 1 and even numbers into their halves.

So given a certain number, x, if the number is even the value that f(x) returns (or evaluates) is x/2.

Otherwise (the number is odd and) f(x) evaluates to: 3x + 1.

Let's try some examples:

and so forth. I hope that it's clear now how f works.

The Iterative 3x + 1 Mapping

Now that we have f let's define the following process: for any given positive and integer number x to iteratively apply f to it means to compute

x1 = f(x)
then
x2 = f(x1)
then
x3 = f(x2)
then
x4 = f(x3)
then
x5 = f(x4)
and so on for ever, or until one of the computed values is 1.

Let's say that after p steps xp reaches 1. Then we call p the cost of x as it is essentially equal to the number of steps it takes to take x to 1 through the repeated application of f.

Let's see some examples.

If we look at 3 then we have

So the cost of 3 is 7.

Let's compute some more costs:

And so forth.

Now we should not forget that we are studying the programming of computers in Java so the question becomes: can we take advantage of that and program one to compute the cost of any number x through the iterative 3x + 1 mapping, instead of us doing all the calculations by hand?

The answer is of course: yes.

The Flow Diagram

It looks like the whole process could be described like this:

Look at this flow diagram a little. Verify that it indeed matches your intuition and understanding about the process that we have described. Note the initialization step, in red; the conditions, or tests, marked in blue. And the final question about the cost of the process...

How do we count the steps?

What is the value of x at the end of the process?

Coding the Flow Diagram in Java

Here's a first draft:

public class Mapping {
  public static void main(String[] args) {
    int x = ...; 
    while (x != 1) {
      if (x is even) {
        x = x / 2; 
      } else {
        x = 3 * x + 1; 
      } 
    } 
    // ... and the cost? 
  } 
}
Let's add a counting aspect to the flow diagram.

So we enhance the source code:
public class Mapping {
  public static void main(String[] args) {
    int x = ...; 
    int count = 0;
    while (x != 1) {
      if (x is even) {
        x = x / 2; 
      } else {
        x = 3 * x + 1; 
      } 
      count = count + 1; 
    } 
    // ... and the cost? 
    System.out.print("The cost is: "); 
    System.out.println(count); 
  } 
}
Now let's notice that: Regarding the last observation we have two choices: We will use this second method here.

We also note that x % 2 == 0 returns true if and only if x is even so we might as well use it where we want to test whether x is even or not.

For the rest of this section we won't present any flow chart, and we will be working with the source code only and present subsequent refinements of it until we have the final product, that we can compile, and run, to test.

So our next version is able to compute the cost of x while also reporting the value at the end of the iterative process, as well.

public class Mapping {
  public static void main(String[] args) {
    int x = ...; 
    int originalValue = x; 
    int count = 0;
    while (x != 1) {
      if (x % 2 == 0) {
        x = x / 2; 
      } else {
        x = 3 * x + 1; 
      } 
      count = count + 1;
    } 
    System.out.print("The cost of ");
    System.out.print(originalValue); 
    System.out.print("is: "); 
    System.out.println(count); 
  } 
}
But how do we initialize x?

Command Line Arguments

To run a Java program you need to create a .class file with javac. You then use java to run it. In our case for the Mapping program we'd have the following:

javac Mapping.java
followed by
java Mapping
Now the news is that if you type a sequence of strings on this last command line following the name of the class Java is willing to collect them in an array (or ordered collection) of strings and pass it to your program's main method. So all you need to clarify is how you can get to these strings to use them.

The secret is that they will be numbered starting from 0 and they will be available in args[0], args[1], and so on, depending on how many we typed.

So if we type the following:

java Mapping john adrian susan
the three strings will be available for us inside main as follows: It doesn't matter if we choose to ignore this in main (as we've been doing so far) Java still prepares them for us as described above.

Another example, if we type:

java Mapping a aa aaa a
then inside the program One more example, if we type:
java Mapping 123 
then inside the program and of course if we type
java Mapping
then args is empty.

For our purpose (initializing the x to compute the cost of the iterative mapping on it) typing the number of interest on the command line like this:

java Mapping 10
would be what we want.

To get it we need only look into args[0].

To use it as an int though, we need to convert it from the String representation that it currently is in.

We do that using a function parseInt from the Integer class. (Using it is just like using the println method from System.out)

Therefore the program becomes:

public class Mapping {
  public static void main(String[] args) {
    int x = Integer.parseInt(args[0]); 
    int originalValue = x; 
    int count = 0;
    while (x != 1) {
      if (x % 2 == 0) {
        x = x / 2; 
      } else {
        x = 3 * x + 1; 
      } 
      count = count + 1;
    } 
    System.out.print("The cost of ");
    System.out.print(originalValue); 
    System.out.print("is: "); 
    System.out.println(count); 
  } 
}
You know how to run this program, you've seen it being run in lab notes 2.

Here's an example on Unix:

frilled.cs.indiana.edu%javac Mapping.java
frilled.cs.indiana.edu%java Mapping 3
The cost of 3is: 7
frilled.cs.indiana.edu%java Mapping 16
The cost of 16is: 4
frilled.cs.indiana.edu%java Mapping 13
The cost of 13is: 9
frilled.cs.indiana.edu%
So as you can see the output of the program can be improved a tiny little bit.

Comments

We've used // to write comments in the program.

The text that follows a double slash to the end of the line is ignored by the compiler, so it's as if it didn't exist for Java. It can be used however to write down comments that will help programmers to make sense out of your source code.

Sweeping a Range of Numbers

Let's say that given x we can compute the cost of x and print it. The homework asks you to be able to sweep a whole range of numbers and print each one's cost.

This could be easily achieved using a for loop.

public class Syracuse {
  public static void main(String[] args) {
    int startingValue = ...; 
    int endingValue = ...; 
    for (int x = startingValue; x <= endingValue; x += 1) {
      ... compute and report the cost of x as before 
    } 
  } 
}
We should obviously be getting the values for the border of the range from the command line:
public class Syracuse {
  public static void main(String[] args) {
    int startingValue = Integer.parseInt(args[0]); 
    int endingValue   = Integer.parseInt(args[1]); 
    for (int x = startingValue; x <= endingValue; x += 1) {
      // ... compute the cost of x as before 
      int originalValue = x; 
      int count = 0;
      while (x != 1) {
        if (x % 2 == 0) {
          x = x / 2; 
        } else {
          x = 3 * x + 1; 
        } 
        count = count + 1;
      }     
      System.out.print("The cost of ");
      System.out.print(originalValue); 
      System.out.print(" is: "); 
      System.out.println(count);
    } 
  } 
}
Note that the program above is almost correct. What's missing?

(It is important to restore the value of x to the originalValue for the iteration so that it can be incremented by one to obtain a new number, the next number in the range.)

Finishing the Program

As we get ready to finish this assignment we need to add one more feature to this program. It is supposed to also report the number with the highest cost in the range and its cost.

What do you think about this flow diagram?

Is it going to work?

Can you code it in Java?

How can we enhance it to report the number as well, rather than just the maximum cost in the range?

The answer will be given in class today.


Last updated: January 25, by Adrian German