Arithmetic Calculations

You store the result of a calculation in a variable by using an assignment statement. An assignment statement consists of a variable name followed by an assignment operator, followed by an arithmetic expression, followed by a semicolon. Here is a simple example of an assignment statement:

numFruit = numApples + numOranges; // Calculate the total fruit

Here, the assignment operator is the = sign. The value of the expression to the right of the = sign is calculated and stored in the variable that appears to the left of the = sign. In this case, the values in the variables numApples and numOranges are added together and the result is stored in the variable numFruit. Of course, we would have to declare all three variables before this statement.

Incrementing a variable by a given amount is a common requirement in programming. Look at the following assignment statement:

numApples = numApples + 1;

The result of evaluating the expression on the right of the = is one more than the value of numApples. This result is stored back in the variable numApples, so the overall effect of executing the statement is to increment the value in numApples by 1. We will see an alternative, more concise, way of producing the same effect shortly.

You can write multiple assignments in a single statement. Suppose you have three variables a, b, and c, of type int, and you want to set all three to 777. You can do this with the statement:

a = b = c = 777;

Note that an assignment is different from initialization in a declaration. Initialization causes a variable to have the value of the constant that you specify when it is created. An assignment involves copying data from one place in memory to another. For the assignment statement above, the compiler will have allocated some memory (4 bytes) to store the constant 777 as type int. This value will then be copied to the variable c. The value in c will be extracted and copied to b. Finally the value in b will be copied to a. (However, strictly speaking, the compiler may optimize these assignments when it compiles the code to reduce the inefficiency of performing successive assignments of the same value in the way I have described.)

With simple assignments of a constant value to a variable of type short or byte, the constant will be stored as the type of the variable on the left of the =, rather than type int. For example:

short value = 0;

value = 10;

This declaration, when compiled and run, will allocate space for the variable value, and arrange for its initial value to be 0. The assignment operation needs to have 10 available as an integer literal of type short, occupying 2 bytes, because value is of type short. The value 10 will then be copied to the variable value.

Now let's look in more detail at how we can perform calculations with integers.

Integer Calculations

The basic operators you can use on integers are +, -, *, and /, which have the usual meanings - add, subtract, multiply, and divide, respectively. Each of these is a binary operator; that is, they combine two operands to produce a result, 2 + 3 for example. An operand is a value to which an operator is applied. The priority or precedence that applies when an expression using these operators is evaluated is the same as you learnt at school. Multiplication and division are executed before any addition or subtraction operations, so the expression:

20 - 3*3 - 9/3

will produce the value 8, since it is equivalent to 20 - 9 - 3.

As you will also have learnt in school, you can use parentheses in arithmetic calculations to change the sequence of operations. Expressions within parentheses are always evaluated first, starting with the innermost when they are nested. Therefore the expression:

(20 - 3)*(3 - 9)/3

is equivalent to 17*(-6)/3 which results in -34.

Of course, you use these operators with variables that store integer values as well as integer literals. You could calculate a value for area of type int from values stored in the variables length and breadth, also of type int, by writing:

area = length * breadth;

The arithmetic operators we have described so far are binary operators, so called because they require two operands. There are also unary versions of the + and - operators that apply to a single operand to the right of the operator. Note that the unary - operator is not just a sign, as in a literal such as -345, it is an operator that has an effect. When applied to a variable it results in a value that has the opposite sign to that of the value stored in the variable. For example, if the variable count has the value -10, the expression -count has the value +10. Of course, applying the unary + operator to the value of a variable results in the same value.

Let's try out some simple arithmetic in a working console application.

Try It Out - Apples and Oranges (or Console Yourself)

Key in this example and save it in a file Fruit.java. You will remember from the last chapter that each file will contain a class, and that the name of the file will be the same as that of the class with the extension .java. Store the file in a directory that is separate from the hierarchy containing the SDK. You can give the directory any name that you want, even the name Fruit if that helps to identify the program that it contains.

public class Fruit {

public static void main(String[] args) {

// Declare and initialize three variables

int numOranges = 5; // Count of oranges

int numApples = 10; // Count of apples

int numFruit = 0; // Count of fruit

numFruit = numOranges + numApples; // Calculate the total fruit count

// Display the result

System.out.println("A totally fruity program");

System.out.println("Total fruit is " + numFruit);

}

}

Just to remind you, to compile this program using the SDK, first make sure that the current directory is the one containing your source file, and execute the command:

javac Fruit.java

As we noted in the previous chapter, you may need to use the -classpath option if the CLASSPATH environment variable has been defined. If there are no errors, this will generate a file, Fruit.class, in the same directory, and this file contains the byte codes for the program. To execute the program you then invoke the Java interpreter with the class name for your application program:

java Fruit

In some Java development environments, the output may not be displayed long enough for you to see it. If this is the case, you can add a few lines of code to get the program to wait until you press Enter before it ends. The additional lines to do this are shown shaded in the following listing:

import java.io.IOException; // For code that delays ending the program

public class Fruit {

public static void main(String[] args) {

// Declare and initialize three variables

int numOranges = 5; // Count of oranges

int numApples = 10; // Count of apples

int numFruit = 0; // Count of fruit

numFruit = numOranges + numApples; // Calculate the total fruit count

// Display the result

System.out.println("A totally fruity program");

System.out.println("Total fruit is " + numFruit);

// Code to delay ending the program

System.out.println("(press Enter to exit)");

try {

System.in.read(); // Read some input from the keyboard

} catch (IOException e) { // Catch the input exception

return; // and just return

}

}

}

We won't go into this extra code here. If you need to, just put it in for the moment. You will understand exactly how it works later in the book.

The stuff between parentheses following main - that is String[] args - provides a means of accessing data that passed to the program from the command line when you run it. We will be going into this in detail later on so you can just ignore it for now, though you must always include it in the first line of main().

All that additional code in the body of the main() method just waits until you press Enter before ending the program. If necessary, you can include this in all of your console programs to make sure they don't disappear before you can read the output. It won't make any difference to how the rest of the program works. We will defer discussing in detail what is happening in the bit of code that we have added until we get to exceptions in Chapter 7.

If you run this program with the additional code, the output will be similar to the following window:

The basic elements in the original version of the program are shown below:

Our program consists of just one class, Fruit, and just one method, main(). Execution of an application always starts at the first executable statement in the method main(). There are no objects of our class Fruit defined, but the method main() can still be executed because we have specified it as static. The method main() is always specified as public and static and with the return type void. We can summarize the effects of these on the method as:

public

Specifies that the method is accessible from outside the Fruit class.

static

Specifies that the method is a class method that is to be executable, even though no class objects have been created. (Methods that are not static can only be executed for a particular object of the class, as we will see in Chapter 5.)

void

Specifies that the method does not return a value.

Don't worry if these are not completely clear to you at this point - you will meet them all again later.

The first three statements in main() declare the variables numOranges, numApples, and numFruit to be of type int and initialize them to the values 5, 10, and 0 respectively. The next statement adds the values stored in numOranges and numApples, and stores the result, 15, in the variable numFruit. We then generate some output from the program.

Producing Output

The next two statements use the method println() which displays text output. The statement looks a bit complicated but it breaks down quite simply:

The text between double quotes, "A totally fruity program", is a character string. Whenever you need a string constant, you just put the sequence of characters between double quotes.

You can see from the annotations above how you execute methods that belong to an object. Here we execute the method println() which belongs to the object out, which, in turn, is a static variable of the class System. Because the object out is static, it will exist even if there are no objects of type System in existence. This is analogous to the use of the keyword static for the method main().

Most objects in a program are not static members of a class though, so calling a method for an object typically just involves the object name and the method name. For instance, if you guessed from the last example that to call the putHatOn() method for an object cowboyHat, of type Hat introduced in Chapter 1, you would write:

cowboyHat.putHatOn();

you would be right. Don't worry if you didn't though. We will be going into this again when we get to look at classes in detail. For the moment, any time we want to output something as text to the console, we will just write,

System.out.println( whateverWeWantToDisplay );

with whatever data we want to display plugged in between the parentheses.

Thus the second statement in our example:

System.out.println("Total fruit is " + numFruit);

outputs the character string "Total fruit is " followed by the value of numFruit converted to characters, that is 15. So what's the + doing here - it's obviously not arithmetic we are doing, is it? No, but the plus has a special effect when used with character strings - it joins them together. But numFruit is not a string, is it? No, but "Total fruit is " is, and this causes the compiler to decide that the whole thing is an expression working on character strings. It therefore converts numFruit to a character string to be compatible with the string "Total fruit is " and tacks it on the end. The composite string is then passed to the println() method. Dashed clever, these compilers.

If you wanted to output the value of numOranges as well, you could write:

System.out.println("Total fruit is " + numFruit

+ " and oranges = " + numOranges);

Try it out if you like. You should get the output:

Total fruit is 15 and oranges = 5

Integer Division and Remainders

When you divide one integer by another and the result is not exact, any remainder is discarded, so the final result is always an integer. The division 3/2, for example, produces the result 1, and 11/3 produces the result 3. This makes it easy to divide a given quantity equally amongst a given number of recipients. To divide numFruit equally between four children, you could write:

int numFruitEach = 0; // Number of fruit for each child

numFruitEach = numFruit/4;

Of course, there are circumstances where you may want the remainder and on these occasions you can calculate the remainder using the modulus operator, %. If you wanted to know how many fruit were left after dividing the total by 4, you could write:

int remainder = 0;

remainder = numFruit % 4; // Calculate the remainder after division by 4

You could add this to the program too if you want to see the modulus operator in action. The modulus operator has the same precedence as multiplication and division, and is therefore executed in a more complex expression before any add or subtract operations.

The Increment and Decrement Operators

If you want to increment an integer variable by one, instead of using an assignment you can use the increment operator, which is written as two successive plus signs, ++. For example, if you have an integer variable count declared as:

int count = 10;

you can then write the statement:

++count; // Add 1 to count

which will increase the value of count to 11. If you want to decrease the value of count by 1 you can use the decrement operator, --:

--count; // Subtract 1 from count

At first sight, apart from reducing the typing a little, this does not seem to have much of an advantage over writing:

count = count - 1; // Subtract 1 from count

One big advantage of the increment and decrement operators is that you can use them in an expression. Try changing the arithmetic statement calculating the sum of numApples and numOranges in the previous example:

public class Fruit {

public static void main(String[] args) {

// Declare and initialize three variables

int numOranges = 5;

int numApples = 10;

int numFruit = 0;

// Increment oranges and calculate the total fruit

numFruit = ++numOranges + numApples;

System.out.println("A totally fruity program");

// Display the result

System.out.println("Value of oranges is " + numOranges);

System.out.println("Total fruit is " + numFruit);

}

}

The lines that have been altered or added have been highlighted. In addition to the change to the numFruit calculation, an extra statement has been added to output the final value of numOranges. The value of numOranges will be increased to 6 before the value of numApples is added, so the value of fruit will be 16. You could try the decrement operation in the example as well.

A further property of the increment and decrement operators is that they work differently in an expression depending on whether you put the operator in front of the variable, or following it. When you put the operator in front of a variable, as in the example we have just seen, it's called the prefix form. The converse case, with the operator following the variable, is called the postfix form. If you change the statement in the example to:

numFruit = numOranges++ + numApples;

and run it again, you will find that numOranges still ends up with the value 6, but the total stored in numFruit has remained 15. This is because the effect of the postfix increment operator is to change the value of numOranges to 6 after the original value, 5, has been used in the expression to supply the value of numFruit. The postfix decrement operator works similarly, and both operators can be applied to any type of integer variable.

As you see, no parentheses are necessary in the expression numOranges++ + numApples. You could even write it as numOranges+++numApples and it will still mean the same thing but it is certainly a lot less obvious what you mean. You could write it as (numOranges++) + numApples if you want to make it absolutely clear where the ++ operator belongs. It is a good idea to add parentheses to clarify things when there is some possibility of confusion.

Computation with Shorter Integer Types

All the previous examples have quite deliberately been with variables of type int. Computations with variables of the shorter integer types introduce some complications. With arithmetic expressions using variables of type byte or short, all the values of the variables are first converted to type int and the calculation is carried out in the same way as with type int - using 32-bit arithmetic. The result will therefore be type int - a 32-bit integer. As a consequence, if you change the types of the variables numOranges, numApples, and numFruit in the original version of the program to short, for example:

short numOranges = 5;

short numApples = 10;

short numFruit = 0;

then the program will no longer compile. The problem is with the statement:

numFruit = numOranges + numApples;

Since the expression numOranges + numApples produces a 32-bit result, the compiler cannot store this value in numFruit, as the variable numFruit is only 16-bits long. You must modify the code to convert the result of the addition back to a 16-bit number. You do this by changing the statement to:

numFruit = (short)(numOranges + numApples);

The statement now calculates the sum of numOranges and numApples and then converts or casts it to the type short before storing it in numFruit. This is called an explicit cast, and the conversion process is referred to as casting. The cast to type short is the expression (short), and the cast applies to whatever is immediately to the right of (short) so the parentheses around the expression numOranges + numApples are necessary. Without them the cast would only apply to the variable numOranges, which is a short anyway, and the code would still not compile. Similarly, if the variables here were of type byte, you would need to cast the result of the addition to the type byte.

The effect of the cast to short is just to take the least significant 16 bits of the result, discarding the most significant 16 bits. The least significant bits are those at the right hand end of the number because the bits in a binary number in Java increase in value from right to left. Thus the most significant bits are those at the left hand end. For the cast to type byte only the least significant 8 bits are kept. This means that if the magnitude of the result is such that more than 16 bits are necessary to represent it (or 8 bits in the case of a cast to byte), your answer will be wrong. You will get no indication from the compiler that this has occurred because it was you, after all, that expressly specified the cast and the compiler assumes that you know what you are doing. You should therefore avoid explicit casts in your programs unless they are absolutely essential.

An integer arithmetic operation involving a value of type long will always be carried using 64-bit values. If the other number in such an operation is not of type long, it will be cast to long before the operation is executed. For example:

long result = 0;

long factor = 10L;

int number = 5;

result = factor*number;

To execute the last statement, because the variable, factor, is of type long, the multiplication will be carried out using long values. The value stored in the variable, number, will be converted to type long, and that will be multiplied by the value of factor.

All other integer arithmetic operations involving types other than long are carried out with 32-bit values. Thus, you only really need to consider two kinds of integer literals:

The type long for operations with 64-bit values where the value has an L appended

The type int for operations with 32-bit values for all other cases where there is no L at the end of the number

Errors in Integer Arithmetic

If you divide an integer value by zero, no sensible result can be produced so an exception will be thrown. An exception is the way of signaling errors in Java that we will discuss in detail in Chapter 7. Using the % operator with a variable or expression for the right hand operand that has a zero value will also cause an exception to be thrown.

Note that if an integer expression results in a value that is outside the range of the type of the result, the result will be truncated to the number of bits for the type you are using and therefore will be incorrect, but this will not be indicated in any way. It is up to you to make sure that the integer types that you are using in your program are always able to accommodate any value that might be produced by your calculations. Problems can arise with intermediate results in some situations. Even when the ultimate result of an expression is within the legal range, if any intermediate calculation is outside the range it will be truncated causing an incorrect result to be produced. To take a trivial example - if you multiply 1000000 by 2000000 and divide by 500000 using type int, you will not obtain the correct result if the multiplication is executed first, because the result of the multiplication exceeds the maximum that can be stored as type int. Obviously where you know this sort of problem can occur, you may be able to circumvent it by using parentheses to make sure the division takes place first - but you need to remember that integer division produces an integer result, so a different sequence of execution can produce a different answer.

Floating Point Calculations

The four basic arithmetic operators, +, -, *, /, are also available for use in floating point expressions. We can try some of these out in another version of the Fruit program which we'll call AverageFruit.

Try It Out - Average Fruit

Make the following changes to the Fruit.java file, and save this as AverageFruit.java. If necessary, you can add in the code we used earlier to make the program wait for the Enter key to be pressed before finishing.

public class AverageFruit {

public static void main(String[] args) {

// Declare and initialize three variables

double numOranges = 50.0E-1; // Initial value is 5.0

double numApples = 1.0E1; // Initial value is 10.0

double averageFruit = 0.0;

averageFruit = (numOranges + numApples) / 2.0;

System.out.println("A totally fruity program");

System.out.println("Average fruit is " + averageFruit);

}

}

This will produce the output:

A totally fruity program

Average fruit is 7.5

The program just computes the average number of fruits by dividing the total by 2.0.

Important As you can see, we have used various representations for the initializing values for the variables in the program, which are now of type double. It's not the ideal way to write 5.0 but at least it demonstrates that you can write a negative exponent value.

Other Floating Point Operators

You can use ++ and -- with floating point variables, and they have the same effect as with integer variables, incrementing or decrementing the floating point variable to which they are applied by 1.0. You can use them in prefix or postfix form, and their operation in each case is the same as with integer variables.

You can apply the modulus operator, %, to floating point values too. For the operation.

floatOperand1 % floatOperand2

the result will be the floating point remainder after dividing floatOperand2 into floatOperand1 an integral number of times. For example, the expression 12.6 % 5.1 will give the result 2.4.

Error Conditions in Floating Point Arithmetic

There are two error conditions that are signaled by a special result value being generated. One occurs when a calculation produces a value which is outside the range that can be represented, and the other arises when the result is mathematically indeterminate, such as when your calculation is effectively dividing zero by zero.

To illustrate the first kind of error we could use a variable to specify the number of types of fruit. We could define the variable:

double fruitTypes = 2.0;

and then rewrite the calculation as:

averageFruit = (numOranges + numApples) / fruitTypes;

This in itself is not particularly interesting, but if we happened to set fruitTypes to 0.0, the output from the program would be:

A totally fruity program

Average fruit is Infinity

The value Infinity indicates a positive but effectively infinite result, in that it is greater than the largest number that can be represented as type double. A negative infinite result would be output as-Infinity. You don't actually need to divide by zero to produce this effect; any calculation, that generates a value that exceeds the maximum value that can be represented as type double will have the same effect. For example, repeatedly dividing by a very small number, such as 1.0E-300, will yield an out-of-range result.

If you want to see what an indeterminate result looks like, you can replace the statement to calculate averageFruit with:

averageFruit = (numOranges - 5.0)/(numApples - 10.0);

This statement doesn't make much sense but it will produce an indeterminate result. The value of averageFruit will be output as NaN. This value is referred to as Not-a-Number, indicating an indeterminate value. A variable with an indeterminate value will contaminate any subsequent expression in which it is used, producing the same result of NaN.

A value that is Infinity or -Infinity will be unchanged when you add, subtract, or multiply by finite values, but if you divide any finite value by Infinity or -Infinity the result will be zero.

_________________________

My New site

OpenEyes