Essential data handling
IMPLICIT NONE
3.3 Arithmetic expressions and assignment
Once we have declared one or more variables then we can start to use them to solve problems. First, however, we must establish how particular values are stored in the memory locations associated with the specified variables.
In fact, there are only two ways in which a variable can be given a value during the execution of a program - by assignment or by aREAD statement. We met the READ statement in Chapter 2, and will discuss it in some detail in the next section; however, by far the most common means of giving a value to a variable is through an assignment statement. This takes the form
name = expression
where name is the name of a variable, and expression is an arithmetic, or other, expression which will be evaluated by the computer to calculate the value to be assigned to the variable name. Thus the statement
a = b
+
ctakes the value currently stored in b, adds to it the value currently stored in c, and stores the resulting value in a.
If a, band c are all real variables, and the values in band c were 2.8 and 3.72 before the statement was obeyed then the value assigned to a would be6.52 - or rather it would be a very close approximation to 6.52, remembering that real arithmetic is always an approximation. Similarly, if a, band c are all integer variables, and the values in band c were 17and 391 before the statement was obeyed then the value assigned to a would be408; in this case the answer would, of course, be exact.
Figures 3.5 and 3.6 illustrate what has happened, by reference to the storage model used earlier, but what about the situation shown in Figure 3.77 In
a=b+c
Figure 3.5 Real arithmetic and assignment.
46 Essential data handling
a=b+c
Figure 3.6 Integer arithmetic and assignment.
this example, the expression uses two real variables, and so the result is clearly real. However the variable a is an integer and so cannot hold a real value.
In this situation the result of the expression is truncated to an integer by, in effect, throwing away the fractional part, or, more formally, by rounding towards zero. Thus, if the values in band c were 2.8 and 3.72 before the statement was obeyed, as before, then the value of the expression would be 6.52, which would be truncated to 6 before being assigned to a.
In the reverse case, where the value of the expression is an integer but the variable to be assigned the value is real, there is less of a problem since the integer result can easily be converted to its real equivalent without any loss of accuracy unless it is so large that it has more precision than a floating-point number can provide. For example, using the hypothetical computer used in Section 3.1 the integer number 12345678 has eight digits of precision and would need to be converted to 0.123457 X 108 (or 12345700.0).
A related problem occurs when not all of the entities making up the expression are of the same type, for example if b were real, while c were integer.
In this case the rule is quite simple, namely that the integer is converted to real before the calculation is carried out. (This is an oversimplification, to which we shall return shortly, but it is sufficiently accurate for the present.)
Figure 3.7 Mixed-mode assignment.
Arithmetic expressions and assignment 47
Operator Meaning
+ addition
subtraction
*
multiplication/ division
**
exponentiation (or 'raising to the power of')Figure 3.8 Arithmetic operators in Fortran.
We must now examine the form of an arithmetic expression in more detail. As in mathematics, an arithmetic expression is created by use of the five primary arithmetic operations - addition, subtraction, multiplication, division and exponentiation (or 'raising one number to the power of another'). Although the addition and subtraction operators use the conventional mathematical operators + and -, it is not possible to express the other three operations in quite the same way as in conventional mathematics. Figure 3.8 shows the symbols used in Fortran.
We may create expressions of arbitrary complexity, subject to the limit on the length of a statement, by means of these operators, such as
a = b+c*d/e-f**g/h+i*j+k
However it is not at all obvious, at first sight, how the above expression will be evaluated!
In this situation, Fortran assigns the same priorities to operators as does mathematics, namely that exponentiation is carried out first, followed by multiplication and division, followed by addition and subtraction, as shown in Figure 3.9.
Within the same level of priority, addition and subtraction or multiplication and division, evaluation will proceed from left to right, except in
Operator Priority
** High
*and / Medium + and - Low
Figure 3.9 Arithmetic operator priorities.
48 Essential data handling
the case of exponentiation, where evaluation proceeds from right to left. Thus the evaluation of the above expression proceeds as follows:
(1) Calculate £**g and save it in temp_l (2) Calculate c*d and save it in temp_2 (3) Calculate temp_2/e and save it in temp_3 (4) Calculate temp_l/h and save it in temp_4 (5) Calculate i*j and save it in temp_5 (6) Calculate b+temp_3 and save it in temp_6 (7) Calculate temp_6-temp_4 and save it in temp_7 (8) Calculate temp_7+temp_5 and save it in temp_B (9) Calculate temp_B+k and~store it in a
In practice, many of the temporary variables temp_l ... temp_B will not actually be used as the computer will keep the intermediate results in special high-speed memory locations (called registers) to high-speed up the calculation, but the principle is correct - namely that the calculation proceeds step by step with each step consisting of the evaluation of a sub-expression consisting of one operator having two operands.
This leads us to a refinement of the earlier statement regarding what happens in a mixed-mode expression, where not all the operands are of the same type. The evaluation of the expression proceeds as already defined until a sub-expression is to be evaluated which has two operands of different types. At this point, and not before, the integer value is converted to real. The importance of this can be seen by considering the evaluation of the statement
a = b*c/d
where bis a real variable whose value is100.0, while c andd are integers having the values 9 and 10,respectively.
Following the rules that have been already described, the value of b*c is first evaluated, with the value of c being first converted to the real value 9.0, to give an intermediate result of900.0, after which the value ofdis converted to its real equivalent before the division is carried out, to give a result to be assigned to a of 90.0.
Now consider what would have happened if the expression had been written in the different, but mathematically identical, way
a = c/d*b
Now, when the first operation is carried out both the operands are integers and so the sub-expression c/d is evaluated as an integer operation. Since integers can have no fractional parts the same procedure is carried out as was described for
Arithmetic expressions and assignment 49 assignment, namely the mathematical result (0.9) is truncated to give an
intermediate result of zero. This is then converted to its real equivalent (O.O!) before being multiplied by the real value ofb, but it is already too late, and the result that will be assigned to a is also zero.
This phenomenon, known as integer division for obvious reasons, has caught out many a programmer (including all of the authors at some time in their careers!). In general, integer division is to be avoided except in situations where programmers know exactly what they are doing and wish to take advantage of the automatic truncation. Normally, however, it is preferable to carry out this type of arithmetic using real arithmetic and then deal with the result as required at the end of the calculation.
The reader should not assume, however, that the order of evaluation does not matter in real arithmetic, for consider the following statement:
w = x-y+z
where x, y and z all have the values 5.678. Clearly the correct value for assignment to w is also 5.678, and with the expression written as above this is, indeed, the result. However, consider what might happen if the statement was written in the mathematically identical form
w = x+z-y
and the program was executed on a computer which only held real numbers to four significant digits. In this case the first operation (5.678
+
5.678) would result in a 'true' value of 11.356 which would be saved (to four significant digits) as 11.36 before the subtraction took place leading to a result of5.682 - an error of 0.004, or 0.07% on a simple addition and subtraction!In practice, because modem computers carry out their arithmetic in special areas of memory capable of much greater precision than the main memory, this particular example would present no difficulty, but the principle that order of evaluation matters is an important one which will be taken up in more detail in Chapter 10.
We have seen that long expressions can become difficult to read and that the order of evaluation is often important; there are, however, two steps that can be taken to improve matters.
The first of these involves the use of parentheses which, just as in mathematics, alter the order of evaluation. Thus the statement
w = x*(z-y)
will result in the evaluation of the sub-expression z-y first, with the result being multiplied by x to obtain the value to be assigned to w.
50 Essential data handling
The other thing that can be done is purely cosmetic and involves the use of spaces to make expressions more readable. For example, the expression used earlier in this section could be made easier to read and understand by writing it as
a =b
+
c*d/e - (f**g)/h+
i*j+
kThe spaces are purely for the human reader and are ignored by the Fortran compiler. In this instance, the parentheses are also only for the benefit of the human reader since the exponentiation would, in any case, be carried out first. We shall use spaces around the lowest priority operators in this way in most of the programs in the remainder of this book, but it must be emphasized that this is merely the authors' own style; programmers will develop their own styles as their experience grows.
There are two remaining points to be made at this stage concerning arithmetic expressions.
The first of these concerns the addition and subtraction operators. All five operators have been presented as binary operators thus far; that is they have always had two operands. This is always true of the multiplication, division and exponentiation operators, but the add!tion and subtraction operators can also be used as unary operators, having only one argument:
p = -q x = +y
The meaning of these unary operators is obvious and the result is identical to the binary case if a zero were placed before the operator.
The other point to be made concerns constants. In Chapter 1, when discussing the concept of a variable by analogy with a glass box containing a ball representing a value, we mentioned that if the box was sealed so that its value could not be changed then it was called a constant. Such constants may have names like variables, as we shall see in Section 3.6, or they may simply appear in a Fortran statement by writing their value. In this latter case they are called literal constants because every digit of the numbers is specified literally. We shall see later that there are other ways of specifying constants.
All the program examples that have been presented in this section have only used variables, but in most expressions there are also some constant items.
Numeric literal constants are usually written in the normal way, and the presence or absence of a decimal point defines the type of the constant.
Thus these are integer constants:
123 1000000 -981
o
List-directed input and output of numeric data 51 while the following are real constants:
1.23 1000.0 -9.81 0.0
There is one exception to the rule that real constants must have a decimal point, namely the exponential form. This is typically used for very small or very large numbers and takes the form
mEe
where m is called the mantissa and e is the exponent. The mantissa may be written either with or without a decimal point, whereas the exponent must take the form of an integer. Thus the value 0.000 001, or 10-6, may be written in any of the following ways:
1E-6 100E-8 O.lE-S etc.