Introduction to Computer Science

Start Lecture #8

Remark: Lab1 part three 40% (we will be covering methods today).

  1. Write the following method
    public static int second(int a, int b, int c, int d);    
          
    This method returns the second largest value of its four parameters.
  2. Write the main method that
  3. Put both methods in a class named Lab1Part3 (which is in a file Lab1Part3.java). Test your lab on any machine you wish.
  4. Copy Lab1Part3.java to i5.nyu.edu. I advise testing it here as well since that is the machine Radhesh will be using.
  5. Mail the file from i5.nyu.edu to the grader, Radhesh Gupta <radheshg@nyu.edu>. Use the correct subject for the message.

Remark: Tutor/E-tutor available.
Anagha Ashok Pande <anagha.pande@nyu.edu> is the tutor/e-tutor for this class. Anagha is reading the mailing list and may respond to questions there and also via the direct email addr above. In addition, Anagha will be in room 328 WWH the following 5 hours each week for office hours. Feel free to drop by with questions, no appointment is necessary. On Mondays and Tuesdays the hours are 1-2:30; on Wednesdays and Thursdays the hour is 11-12.

4.8.3: Monte Carlo Simulation

I hate to take problems straight from the book since you can read it there, but this is too good to pass up.

Calculate π by choosing random points in a square and seeing how many are inside a circle.

Do in class. One solution is here.

4.9: Keywords break and continue

We have already seen break for breaking out of a switch statement.

When break is used inside a loop, it does the analogous thing: namely it breaks out of the loop. That is execution transfers to the first statement after the loop. This works for any of the three forms of loops we have seen: while, do-while, or for.

In the case of nested loops, the break just breaks out of the inner one.

There is an alternate form of break that can be used to break out of many levels of looping or to break out of other constructs as well.

The continue statement can be used only inside a loop. When executed, it continues the loop by ending the current iteration of the body and proceeding to the next iteration. Specifically:

  1. In a while loop, a continue transfers control to the test at the top of the loop.
  2. In a do-while loop, a continue transfers control to the test at the bottom of the loop.
  3. In a for loop, a continue transfers control to the update at the bottom of the loop (from where control transfers to the test at the top).

4.9.1: Displaying Prime Numbers

We want to display the first N primes. Unlike the book, we will

  1. Input N, not have it hardwired.
  2. Try divisors up to only the square root of the candidate prime.

Although the second improvement does make the program much faster for large primes, it is still quite inefficient compared to the best methods, which are quite complicated and use very serious mathematics.

Start it in class.

Homework: Write this program in Java and test it for N=25.

4.10: (GUI) Controlling a Loop with a Confirmation Dialog

Chapter 5: Methods

5.1: Introduction

Like all modern programming languages, Java permits the user to abstract a series of actions, give it a name, and invoke it from several places.

Many programming languages call the abstracted series of actions a procedure, a function, or a subroutine. Java, and some other programming languages, call it a method.

We have seen a method already, namely main().

5.2: Defining a Method

We know how to do this since we have repeatedly defined the main method. The general format of a method definition is.

    modifiers returnType name (list of parameters) { body }
  

For now we will always use two modifiers public static.

The main() method had returnType void since it did not return a value. It also had a single argument, an array of Strings.

The returnType and parameters will vary from method to method.

public static int myAdd(int x, int y) {
  return x+y;
}

On the right we see a very simple method that accepts two int parameters and returns an int result. Note the return statement, which ends execution of the method and optionally returns a value to the calling method.

The type of the value returned will be the returnType named in the method definition.

5.3: Calling a Method (that Returns a Value)

public class demoMethods {
  public static void main(String[]) {
    int a = getInput.nextInt();
    int b = getInput.nextInt();
    System.out.println(myAdd(a,b));
  }
  public static int myAdd(int x, int y) {
    return x+y;
  }
}

We have called a number of methods already. For example getInput.nextInt(), Math.pow(), Math.random(). There is very little difference between how we called the pre-defined methods above and how we call methods we write.

One difference is that if we write a method and call it from a sibling method in the same class, we do not need to mention the class name.

On the right we see a full example with a simple main() method that calls the myAdd() method written above.

Method such as myAdd() that return a value are used in expressions the same way as variables and constants are used, except that they contain a (possibly empty) list of parameters. They act like mathematical functions. Indeed, they are called functions in some other programming languages.

Note that the names of the arguments in the call do NOT need to agree with the names of the parameters in the method definition. For example, how could we possibly have gotten the parameter names we used with Math.pow() correct, since we have never seen the definition?

5.3.1: Call Stacks

The LIFO (Last In, First Out) semantics of method invocation (f calls g and then g calls h, means that, when h returns, control goes back to g, not to f.

Method invocation and return achieves this semantics as follows.

Homework: 5.1, 5.3.

5.4: void Method Example

public class demoMethods {
  public static void main(String[]) {
    int a = getInput.nextInt();
    int b = getInput.nextInt();
    printSum(a,b);
  }
  public static void printSum(int x, int y) {
    System.out.println(x+y);
  }
}

Methods that do not return a value (technically their return type is void) are invoked slightly differently. Instead of being part of an expression, void methods are invoked as standalone statements. That is, the invocation consists of the method name, the argument list, and a terminating semicolon.

An example is the printSum() method is invoked by main() in the example on the right.

Homework: 5.5, 5.9.

5.5: Passing Parameters by Values

Referring to the example above, the arguments a,b in main() are paired with the parameters x,y in printSum in the order given, a is paired with x and b is paired with y.

The result is that the x and y are initialized to the current values in a and b. Note that this works fine if an argument a or b is a complex expression and not just a variable. So printSum(4,a-8) is possible.

public class demoPassByValue {
  public static void main(String[]) {
    int a = 5;
    int b = 6;
    int c = 7;
    tryToAdd(a,b,c);
  }
  public static void tryToAdd(int x, int y, int z) {
    x = y + z;
  }
}

The parameters, however, must be variables.

Java is a pass-by-value language. This means the on invocation the values in the arguments are transmitted to the corresponding parameters, but, at method return, the final values of the parameters are not, repeat NOT sent back to the parameters.

For example the code n the right does not set a to 13.

When we learn about objects and their reference semantics, we will need to revisit this section.

5.6: Modularizing Code

Programs are often easier to understand if they are broken into smaller pieces. When doing so, the programmer should look for self-contained, easy to describe pieces.

public class demoModularizing {
  public static void main(String[] args) {
    // input 3 points (x1,y1), (x2,y2), (x3,y3)
    double perimeter = length(x1,y1,x2,y2) +
      length(x2,y2,x3,y3) + length(x3,y3,x1,y1);
    System.out.println(perimeter);
  }
  public static length(double x1, double y1,
                       double x2, double y2) {
    return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
  }
}

Another advantage is the ability for code reuse. In the very simple example on the right, we want to calculate the perimeter of a triangle specified by giving the (x,y) coordinates of its three vertices.

Of course the perimeter is the sum of the lengths of the three sides and the length of a line is the square root of the sum of the squares of the difference in coordinate values.

Without modularization, we would have one large formula that was the sum of the three square roots.

As written on the right, I abstracted out the length calculation, which in my opinion, makes the code easier to understand.

Other examples are the methods in the Math class. Imagine writing a geometry package and having to code the square root routine each time it was used.

5.7: Problem: Converting Decimals to Hexadecimals

Read.

5.8: Overloading Methods

A very nice feature of Java and other modern languages is the ability to overload method names.

public class DemoOverloading {
  public static void main(String[] args) {
    System.out.printf ("%d %f %f\n", max(4,8),
                       max(9.,3.), max(9,3.));
  }
  public static int max(int x, int y) {
    return x>y ? x : y;
  }
  public static double max(double x, double y) {
    return x>y ? x : y;
  }
  public static double max(int x, double y) {
    return ((double) x)>y ? x : y;
  }
}

Of course if you use a method named max and another named min each with two integer arguments, Java is not confused and invokes max when you write max and invokes min when you write min.

All programming languages do that.

But now look on the right and see three methods all named max, one returning the maximum of two ints one returning the maximum of two double, and the third returning (as a double) the max of an int and a double.

When compiling a method definition javac notes the signature of the method, which for overloading consists of the method name, the number of parameters, and the type of each parameter.

When an overloaded method is called, the method chosen is the one with signature matching the arguments given at the call site.

Technical fine points: Java would coerce a 9 to a double if needed. But if the overloaded method has two signatures, one requiring coercion and the other not, the second is chosen. If the overloaded method has two signature, each with two parameters, having types so that one would require coercing the first argument and the other would require coercing the second argument, the program does not compile.

5.9: the Scope of Variables

The scope of a variable is the portion of the program in which the variable can be referenced.

The rules for scope vary from language to language.

In Java a block is a group of statements enclosed in {}. For example the body of most loops, the body of most then and else clauses of an if, and the body of a method are all blocks. The exceptions are one statement bodies of then clauses, else clauses, and loops that are written without {}.

In Java the scope of a local variable begins with its declaration and continues to the end of the block containing the declaration. We have seen the one exception: if the initialization portion of a for statement contains a declaration, that local variable has scope including the body of the loop.

5.9.A: Nested vs Non-nested Blocks

On the right we see two skeletons. The near right skeleton contains two blocks block1 and block2, neither of which is nested inside the other.

something { |   something {
  block1    |     start of block3
}           |     something {
something { |       block4  
  block2    |     }
}           |   }

In this case it is permitted to declare two variables with the same name, one in block1 and one in block2. These two variables are unrelated. That is, the situation is the same as if they had different names.

On the far right we again see two blocks, but this time block4 is nested inside block3. In this situation it is not permitted to have the same variable name declared in both blocks. Such a program will not compile.

5.10: The Math Class

We have already used a few methods from the Math class.

In addition to various methods, some of which are described below, the Math class defines two important mathematical constants, E, the base of the natural logarithm, and PI, the ratio of a circle's perimeter to its diameter.

public static double sin(double theta)
public static double cos(double theta)
public static double tan(double theta)
public static double asin(double x)
public static double acos(double x)
public static double atan(double x)

public static double toDegrees(double radians) public static double toRadians(double degrees)

5.10.1: Trigonometric Metrics

The six routines on the upper right compute the three basic trig functions and their inverses. In all cases, the angles are expressed in radians.

The two below are used to convert to and from degrees.

5.10.2: Exponent Methods

public static double pow(double a, double b)
public static double sqrt(double a)

public static double log(double x) public static double exp(double x)
public static double log10(double x)

The first routine on the right computes ab. Since the special case of square root, where b=.5 is so widely used it has its own function, which is given next.

Mathematically, logs and exponentials based on Math.E are more important than the corresponding functions using base 10. They come next.

The base 10 exponential is handled with pow, but there is a special function for the base 10 log as shown.

5.10.3: The Rounding Methods

Given a floating point value, one can think of three integer values that correspond to this floating point value.

public static double floor(double x)
public static double ceil(double x)
public static double rint(double x)
  
  1. The floor, i.e., the greatest integer not greater than.
  2. The ceiling, i.e., the least integer not less than.
  3. The nearest integer. What about ties?

The Math class has three methods that correspond directly to these mathematical functions, but return a type of double. They are shown on the upper right. For the third function, ties are resolved toward the even number so rint(-1.5)==rint(-2.5)==-2..

public static int round(float x)
public static long round(double x)

In addition Math has an overloaded method round() that rounds a floating point value to an integer value. The two round method are distinguished by the type of the argument (as normal for overloaded methods). Given a float, round returns an int. Given a double, round returns a long.

This choice prevents the loss of precision, but of course there are many floats and doubles (e.g., 10E30) that are too big to be represented as an ints or longs.

5.10.4: The min, max, and abs Method

These three methods are heavily overloaded, they can be given int, long, float, or double arguments (or, for min and max) one argument of one type and the other of another type.

5.10.5: The random Method

We have already used Math.random() several times in our examples. As mentioned random() returns a double x satisfying 0≤x<1.

To obtain a random integer n satisfying m≤x<n you would write m+(int)((n-m)*Math.random()). For example, to get a random integer 10≤x<100, you write 10+(int)(90*random()).

5.11: Case Study: Generating Random Characters

Let's do one slightly different from the book's.

Print N (assumed an even number) random characters, the odd ones lower case and the even ones upper case.

public class RandomChars {
  public static void main(String[] args) {
    final int n = 1000;     // assumed EVEN
    for(int i=0; i<n/2; i++) {
      System.out.printf("%c", pickChar('a'));
      System.out.printf("%c", pickChar('A'));
    }
  }
  public static char pickChar(char c) {
    return (char)((int)(c)+(26*Math.random()));
  }
}

The program on the right is surprisingly short. The one idea used to create it was the choice of the pickChar() method. This method is given a character and returns a random character between the given argument and 26 characters later. So, when given 'a, it returns a random lower case character and, when given 'A, it returns a random upper case character.

Remember that in Unicode lower case (so called latin) letters are contiguous as are upper case letters.

Be sure you understand the value returned by pickChar().