The Two Numbers Examples

Reading, adding, multiplying and printing

On this page we have some simple examples showing use of numbers and static methods in Java. The programs may be found in the same directory as the "Hello" examples, but to keep it tidy there is a subdirectory called twonums to hold them. So the following directory holds the examples:

/import/teaching/BSc/1st/ItP/twonums

Here is a program which simply reads two numbers, and gives the result of adding them together and multiplying them together:

 1  import java.io.*;
 2
 3  class TwoNums0
 4  {
 5  //  A program that prompts for two numbers then prints their sum and product
 6
 7  public static void main (String[] args) throws IOException
 8  {
 9   int m,n;
10   BufferedReader in = Text.open(System.in);
11   System.out.print("Enter first number: ");
12   m=Text.readInt(in);
13   System.out.print("Enter second number: ");
14   n=Text.readInt(in);
15   System.out.println("Adding the two gives: "+(m+n));
16   System.out.println("Multiplying the two gives: "+m*n);
17  }
18 }
As with the "Hello" examples, the Text input/output class is used to help with input from the Linux window. As this is not a standard part of Java, you will need a copy of the file Text.class in the directory you run the program from (this is for simplicity - there are more sophisticated ways to enable you to reuse code without having a copy in every directory). The readInt method in Text reads an integer, in a similar way to how the readString method read a string. It is used in lines 12 and 14. Line 9 declares two integer variables (Java, like C uses the word int for integer).

You might wonder why line 15 is not:

 System.out.println("Adding the two gives: "+m+n);
but if you tried editing the program to make it that way and then ran it, you would see why. The plus sign would then be treated as the sign for joining two strings together rather than the sign for arithmetic addition. A general rule is that if you see something of the form a+b+c for any a, b or c (or two or four or more terms of course), if one of them is a string, all will be interpreted as a string and joined together. On the other hand, if they are all numbers they will be added together. Enclosing m+n in brackets in line 15 meant it was treated as a separate thing and evaluated by addition before the result was turned into a string and joined to the words "Adding the two gives: ". There is no such problem in line 15 as m*n is evaluated arithmetically before the + is considered (note that in almost all programming language, multiplication is indicated by the * symbol).

An alternative way of writing this would use two new variables to hold the sum and product (only the main method is given here):

  public static void main (String[] args) throws IOException
  {
   int m,n,sum,product;
   BufferedReader in = Text.open(System.in);
   System.out.print("Enter first number: ");
   m=Text.readInt(in);
   System.out.print("Enter second number: ");
   n=Text.readInt(in);
   sum=m+n;
   System.out.println("Adding the two gives: "+sum);
   product=m*n;
   System.out.println("Multiplying the two gives: "+product);
  }
Deciding whether to put an expression in directly or to assign it to a separate variable and then use that variable is a matter of judgement. Code can look cluttered if too many variables are introduced and just used once, on the other hand it can help avoid complicated expressions.

The file TwoNums1.java is given to show there is nothing special about the Text class. It is very similar to TwoNums0.java except it uses a different reader. In this case, the Java program for the reader is given, in file MyReader.java. If you copy TwoNums1.java and MyReader.java into your directory, and enter the Linux command:

javac TwoNums1.java
you will find that since TwoNums1 calls MyReader, the file MyReader.java gets compiled as well so you end up with TwoNums1.class and MyReader.class. MyReader does not create a separate BufferedReader unlike Text. It is meant to be a very simplistic reader, given just for demonstration. You will need to know a little, but not a lot, more Java to see exactly how it works. If you try running the TwoNums0 and TwoNums1 examples, and type in letters rather than numbers at the prompts, you will see another difference between Text and MyReader. Text is sophisticated enough to check for this and ask you to type again, whereas MyReader isn't designed to cope with it and gives strange results. This illustrates an important point: a good program ought to be able to cope in an intelligent way when the program user does something unexpected (and typing in numbers when letters are expected is a good example).

Here's another thing to note - try typing in some very large numbers in response to the prompts. For example, 1000000 and 2000000 (Java does not accept the breaking up of large numbers with commas, so they must be typed just like this). You will find the multiplication gives an unexpected answer. The reason for this is that numbers are stored in a fixed amount of space in Java, which means it can only cope with numbers between a certain limit. In appendix A of Barnes' book "Object-Oriented Programming in Java", it says what these limits are. The same information can be found on page 60 of Bishop's "Java Gently" textbook and on page 144 of Deitel and Deitel's "Java How to Program". As the example shows, a calculation which goes beyond those limits simply results in an erroneous number being returned without anything special happening to let it be known that something has gone wrong.

Java, like C, however, has types which take up more storage space in the computer and hence can store larger numbers. If you replace int on line 9 of TwoNums.java by long a type which stores integers but allocates twice as much space for each as int you will find you have a program which can cope with much larger numbers.

Expressions

Here's a program which calculates the result of a little formula using the two numbers read:
 1  import java.io.*;
 2
 3  class TwoNums2
 4  {
 5  // A program that prompts for two numbers then prints the difference between
 6  //  the two squares.
 7
 8  public static void main (String[] args) throws IOException
 9  {
10   int m,n,d;
11   BufferedReader in = Text.open(System.in);
12   System.out.print("Enter first number: ");
13   m=Text.readInt(in);
14   System.out.print("Enter second number: ");
15   n=Text.readInt(in);
16   d=m*m-n*n;
17   System.out.println("The difference between the two squares is: "+d);
18  }
19 }
If the two numbers are m and n, the value calculated is m2-n2. The only line that's different from what we've seen before is line 16 where the actual calculation is done. The effect of line 16 is to do the arithmetic calculation represented by m*m-n*n substituting m and n by the values those variables contain, then put the result in the variable d. This may seem obvious, but it requires a little thought to see a possible flaw. Suppose m stores 5 and n stores 3. Then m*m-n*n evaluates to 5*5-3*3 which is surely 25-9 which is 16. That is correct.

But suppose it is typed into a calculator:

PRESS 5
PRESS MULTIPLY
PRESS 5
PRESS SUBTRACT
PRESS 3
PRESS MULTIPLY
PRESS 3
PRESS EQUALS
The result is 66.

The reason for the difference is the order in which the arithmetic operations are done. A calculator does them in left-to-right order, so it's really evaluating ((5*5)-3)*3. In other words, it first multiplies the 5 by 5, giving 25, then subtracts the 3 giving 22, then multiplies by 3 giving 66. Another way of thinking of it is as a series of rewrite operations:

d=m*m-n*n
rewrites (by substituting the variable values):
d=5*5-3*3
then by performing the underlined arithmetic:
d=25-3*3
then by performing the next underlined arithmetic:
d=22*3
However, Java, like most programming languages, tackled the arithmetic in a different way. Rather than doing the arithmetic operations in strict left-to-right order, it follows the rule that multiplications must always be done before additions, so the rewrites work:
d=m*m-n*n
rewrites (by substituting the variable values):
d=5*5-3*3
then by performing the underlined arithmetic:
d=25-3*3
then by performing the next underlined arithmetic:
d=22-9
that is, it treats the expression as if it were (m*m)-(n*n).

The general rule is that expressions in brackets are evaluated first, then multiplications and divisions, then additions and subtractions. Or, as Computer Scientists put it, multiplication has a higher precedence than addition. In the case of operators with equal precedence, Java evaluates them in a left-to-right order, so 9-3-1 is (9-3)-1 i.e. 5, rather than 9-(3-1) i.e. 7. Page 713 of the Weiss book has a table giving the complete precedence order of Java operators.

Functions

The next version of the program, in file TwoNums3.java has exactly the same result as the previous one, but illustrates a new concept, the idea of a function:
 1  class TwoNums3
 2  {
 3  // A program that prompts for two numbers then prints the difference between
 4  // the two squares. Uses a separate function to find it.
 5
 6  public static void main (String[] args) throws IOException
 7  {
 8   int m,n,d;
 9   BufferedReader in = Text.open(System.in);
10
11   System.out.print("Enter first number: ");
12   m=Text.readInt(in);
13   System.out.print("Enter second number: ");
14   n=Text.readInt(in);
15   d=diffTwoSquares(m,n);
16   System.out.println("The difference between the two squares is: "+d);
17  }
18
19  public static int diffTwoSquares(int p,int q)
20  {
21   int r;
22   r=p*p-q*q;
23   return r;
24  }
25
26 }
What has happened here is that the formula for calculating the difference between the squares of two numbers has been given a name (diffTwoSquares) and made a separate part of the program, on lines 19-24. In languages like C, this would be termed a function, but as Java is object-oriented it is termed a method. However, a method which is static, indicated by the word static as on line 19, behaves just like a C or Pascal function. We shall explain in more detail the distinction between a function and a standard method elsewhere.

So the class TwoNums3 has two static methods, main and diffTwoSquares. Another name for a static method is a class method. Note we are keeping to the convention generally observed in Java that names made up of several words have the word divisions indicated by starting the new words with capital letters. Java names can't include spaces, but they can include the underscore character, so we could have used diff_two_squares although Java's built-in library avoids that convention. The method main is run when the program is started from Linux, but it may call other methods which may in turn call further methods, and so on. Line 15 is where main calls diffTwoSquares.

A static method works exactly like main except that it takes arguments and produces a return value. Sometimes the arguments are described as the "input" to a function and the return value as its "output", but it's very important to distinguish between this usage of the terms "input" and "output" and the usage which refers to reading or writing from the screen or a file. The function diffTwoSquares could be said to take as input two integers and return as output the difference between their two squares, but this does not mean that it reads two integers or prints the difference of their squares. As you can see, the reading is done in main on lines 11-14, and the writing is also done in main on line 16. diffTwoSquares only does the calculating.

The variables declared inside main (on line 8) are for use in main only and cannot be referred to in diffTwoSquares and the variable declared inside diffTwoSquares (on line 21) is for use in diffTwoSquares only and cannot be referred to in main (there are variables called class variables which are shared across methods in a class, but we won't look at those yet). diffTwoSquares has two extra variables, p and q declared in its header on line 19. When diffTwoSquares is run, p and q are initialised to the values given to them as parameters. In this case, line 15 in main is the call to diffTwoSquares which causes it to be run. The arguments m and n are used to initialise p and q. It is as if instead of line 15 in main, we had:

  p=m;
  q=n;
  r=p*p-q*q;
  d=r;
assuming p, q and r were declared in main. As you can see, the function call is replaced by assignments which match the arguments of the call to the parameters of the function, followed by the code inside the function. The final line which follows this shows how the return value of the function works, the value which is returned inside diffTwoSquares, in this case r, replaces the whole of diffTwoSquares(m,n) in what was the original line d=diffTwoSquares(m,n).

The effect is as if diffTwoSquares were a built-in aspect of Java rather than a part of the program we wrote ourselves. Once the method is given, the call diffTwoSquares(x,y) for x and y not just variables, but any values, including complex expressions, can be used to calculate the difference of the squares of x and y, anywhere in the class where it is given. The word public on the header for diffTwoSquares means that in fact it can be used outside the class TwoNums3 as well - we shall show how that is done shortly.

The header for diffTwoSquares also gives type information on the method. The first int on line 19 states that the value returned by diffTwoSquares is an integer. The second and third int occurring before the names of its two parameters, states that these parameters are integers as well. It is possible in Java to have more than one method with the same name so long as the types of the parameters differ. Which one is used depends on the types of the arguments used when the method is called.

You may note that main has a result type (void) and a parameter, args, with type String[]. The parameters are used to enable command line arguments which we shall discuss later on - in the examples you have seen so far they are not used. The type void is a special type used to indicate that a method does not return a value. A method which simply does some calculations but returns no value is obviously of no use since it has no effect outside itself. However, a method which returns no value but has some additional effect, for example it writes something, does have a use.

Using Functions in other Classes

Here is a program which prompts you for a number and prints that number's square root:
 1  import java.io.*;
 2 
 3  class SquareRootPrinter
 4  {
 5  //  A program that asks for a number and prints its square root
 6
 7  public static void main (String[] args) throws IOException
 8  {
 9   double x,xsq;
10   BufferedReader in = Text.open(System.in);
11   System.out.print("Enter a number: ");
12   x=Text.readDouble(in);
13   xsq=Math.sqrt(x);
14   System.out.println("The square root of "+x+" is "+xsq);
15  }
16 }
The square root is calculated by the call to the function sqrt in line 13. This function comes from Java's library, in class Math which is why the call is written Math.sqrt(x). In fact the full name is java.lang.Math.sqrt, but you don't have to put the java.lang in, nor do you have an import java.lang.* line in, as you have to put an import java.io.* line in to use methods in Java's io package, because the classes in java.lang are treated as if already imported. The Math class contains a variety of mathematical functions, for example trigonometry functions. To see exactly what it contains, you could look it up in a Java reference book, like "Java in a nutshell", or you could look at its on-line documentation, found here. Note that the way a method in the system class Math is called is no different from the way a method in some other class, for example readDouble in Text in line 12 of the above program is called.

The Java programming language is supplemented with an extensive library of predefined classes, known as the API (which stands for "Applications Programming Interface"). Many books and references you will see on Java are actually more on how to use the API than on the core Java language. In this course, however, we shall only consider a small part of the API that is necessary to run the examples used as the aim is to concentrate on the basics.

The method readDouble in Text is, as you might expect from the name, one which reads a double in the way readInt reads an integer. A double is a number which has a fractional part, so you could type in something like 37.32 in response to the prompt. Just as integers have two types, int and long, fractional or floating point numbers have two types float and double, with double taking up more computer store in order to store numbers to more accuracy and to a greater range than float.

The great accuracy of double means the square root is printed out to many decimal places in this program. In practice you may not want to show it to quite so many decimal places, but if you simply print it out by joining it to a string using + you have no choice. The Text class provides methods which enable you to format printing of floating point numbers. Text.writeDouble takes three arguments - the first is the actual floating point number, the second an integer giving the minimum number of characters used to print the number (it will fill out with spaces to reach that figure if necessary, which is useful to give nice layouts), the third is the number of decimal places to which the number is printed. It returns a string which represents the number formatted in that way. So as it takes a double and two integers and returns a string, its header in Text (which you haven't seen as you have only the compiled version) would be:

public static String writeDouble(double num,int align,int frac)
The names used for the arguments are irrelevant, but the types are important to show how it is used. In this case, note that writeDouble returns a vlaue but it does not actually do the printing. The value it returns must be printed using println. So here is a modified version of the main method for SquareRootPrinter:
 1  public static void main (String[] args) throws IOException
 2  {
 3   double x;
 4   String xsqFormat;
 5   BufferedReader in = Text.open(System.in);
 6   System.out.print("Enter a number: ");
 7   x=Text.readDouble(in);
 8   xsqFormat=Text.writeDouble(Math.sqrt(x),5,3);
 9   System.out.println("The square root of "+x+" is "+xsqFormat);
10  }
For illustration, in this case no special variable is declared just to hold the square root, so the call to Math.sqrt occurs inside the call to Text.readDouble, which is perfectly permissible. We could have gone further and not had a special string variable to hold the formatted number, in which case line 4 above is not needed, and lines 8 and 9 would be replaced by:
System.out.println("The square root of "+x+" is "+Text.writeDouble(Math.sqrt(x),5,3));
While this is still reasonable, you can begin to see how complicated expressions may be made more understandable by breaking them up into parts and using temporary variables.

We have already seen the use of Text to give a library of methods useful for text input and output, and Math as Java's own library of useful mathematical functions. We could create our own class to hold a library of functions we find useful. The class TwoNums4 given below works similarly to TwoNums3 but expects the method diffTwoSquares to be in a separate class MyFuncs. For illustration, TwoNums4 extends twoNums3 by also calling on another method, midpoint which simply finds the midpoint between two integers.

 1  import java.io.*;
 2  
 3  class TwoNums4 
 4  {
 5  // A program that prompts for two numbers then prints the difference between
 6  // the two squares, and the midpoint. Uses methods in class MyFuncs to
 7  // calculate them.
 8
 9   public static void main (String[] args) throws IOException
10   {
11    int m,n,d;
12    BufferedReader in = Text.open(System.in);
13    System.out.print("Enter first number: ");
14    m=Text.readInt(in);
15    System.out.print("Enter second number: ");
16    n=Text.readInt(in);
17    d=MyFuncs.diffTwoSquares(m,n);
18    System.out.println("The difference between the two squares is: "+d);
19    d=MyFuncs.midpoint(m,n);
20    System.out.println("The midpoint of the two numbers is: "+d);
21   }
22  }
The class MyFuncs exists in a separate file, called MyFuncs.java:
 1  class MyFuncs 
 2  {
 3  // Miscellaneous functions
 4
 5   public static int diffTwoSquares(int p,int q)
 6   {
 7    return p*p-q*q;
 8   }
 9
10   public static int midpoint(int p,int q)
11   {
12    return (p+q)/2;
13   }
14
15  }
The advantage of this is that, just as we have reused Text whenever we necessary, we can reuse methods from this library in any program we write. The Java language strongly encourages reuse of programming components rather than "reinventing the wheel" by writing completely new programs from scratch each time.

The diffTwoSquares method on lines 5-8 of MyFuncs looks different from the previous one because there is no separate variable to store the calculated value. It is not necessary to have one, return in a method can be followed by any expression. The brackets around p+q on line 12 are needed because / has a higher precedence than +, so p+q/2 would divide q by two then add the result to p whereas what we want is to add p and q and divide the result by two. Another point to note here is that division of integers in Java (like C) always gives an integer result. So if, say, p holds 10 and q holds 15, (p+q)/2 won't evaluate to 12.5. Integer division always rounds down to the nearest integer, so it will in fact give 12. This would be so even if midpoint were written to return a double:

 public static double midpoint(int p,int q)
 {
  return (p+q)/2;
 }
(p+q)/2 with p holding 10 and q holding 15 would evaluate to 12, and 12 would then be converted to the double 12.0. The way to get round this is to use type conversion. If an integer value is preceded by (double) in Java it is converted to the equivalent double value. So, (double)(p+q) is the double equivalent of the integer value of p+q, with our example figures, p+q is the integer 25, while (double)(p+q) is the double 25.0. Dividing a double by an integer gives a double, in this case 12.5.
Matthew Huntbach

These notes were produced as part of the course Introduction to Programming as it was given in the Department of Computer Science at Queen Mary, University of London during the academic years 1998-2001.

Last modified: 13 Oct 2000