

Arithmetic Expressions RATE * HOURS + BONUS
The rules of Fortran have been designed to resemble those of mathematics as far as
possible, especially in determining the order in which the expression is evaluated.
In this example the multiplication would always be carried out before the
addition, not because if comes first, but because it has a higher precedence.
When in doubt, or to over-ride the precedence rules, parentheses can be
used:
(ROOM + DINNER) * 1.15
Sub-expressions enclosed in parentheses are always evaluated first; they can be nested to any reasonable depth. If in doubt, there is no harm in adding parentheses to determine the order of evaluation or to make a complicated expression easier to understand.
Arithmetic expressions can contain any of the five arithmetical operators + - * / ** .
The double asterisk represents exponentiation, i.e. raising a number to a power. Thus
the mathematical expression:
could be represented in Fortran as:
(1.0 + RATE/100.0)**YEARS
(note the explicit decimal points in the constants to make them real values).
Arithmetic expressions can involve operands of different data types: the data type of the result is determined by some simple rules explained below.
Arithmetic expressions can contain arithmetic operands, arithmetic operators, and parentheses. There must always be at least one operand. The operands can belong to any of the four arithmetic data types (integer, real, double precision, or complex); the result also has an arithmetic data type. Operands can be any of the following:
|
|
All literal arithmetical constants used in expressions must be unsigned: this is to
prevent the use of two consecutive operators which is confusing and possibly
ambiguous:
4 / -3.0**-1 (illegal).
The way around this is to use parentheses, for example:
4 / (-3.0)**(-1)
which makes the order of evaluation explicit.
The order of evaluation of an expression is:
A / B / C is
equivalent to (A / B) / C whereas X ** Y ** Z is equivalent to X ** (Y **
Z).
An expression does not have to be evaluated fully if its value can be determined
otherwise: for example the result of:
X * FUNC(G)
can be determined without calling the function FUNC if X happens to be zero.
This will not cause problems if you only use functions that have no side
effects.
If an operator has two operands of the same data type then the result has the
same type. If the operands have different data types then an implicit type conversion
is applied to one of them to bring it to the type of the other. These conversions
always go in the direction which minimises loss of information:
integer
real
complex or double precision
Since there is no way of converting a complex number to double precision type, or vice-versa, without losing significant information, both these conversions are prohibited: an operator cannot have one complex operand and one of double precision type. All other combinations are permitted. These implicit type conversions have the same result as if the appropriate intrinsic function (REAL, DBLE, or CMPLX) had been used. These are described in detail below. Note that the data type of any operation just depends on the two operands involved; the rest of the expression has no influence on it whatever.
Exponentiation is an exception to the type conversion rule: when the exponent is
an integer it does not have to be converted to the type of the other operand and the
result is evaluated as if by repeated multiplication. But if the exponent has any other
data type the calculation is performed by implicit use of the LOG and EXP
functions, thus:
2.0**3
2.0 * 2.0 * 2.0
8.0
2.0**3.0
EXP(3.0 * LOG(2.0))
8.0
The first result will, of course, be computed more rapidly and accurately than the
second. If the exponent has a negative value the result is simply the reciprocal of the
corresponding positive power, thus:
2.0**(-3)
1.0/2.0**3
1.0/8.0
0.125
Note that conversion from real to double precision cannot produce any information not present originally. Thus with a real variable R and a double precision variable D:
R = 1.0 / 3.0 D = R |
Integer division always produces a result which is another integer value: any
fractional part is truncated, i.e. rounded towards zero. This makes it especially
important to provide a decimal point at the end of a real constant even if the
fractional part is zero. For example:
8 / 3
2 -8 / 3
-2 2**(-3)
1/(2**3)
1/8
0
The combination of the two preceding rules may have unexpected effects, for
example:
(-2)**3
-2 * -2 * -2
-8
whereas (-2)**3.0 is an invalid expression as the computer would try to evaluate the
logarithm of -2.0, which does not exist. Similarly, the expression:
3 / 4 * 5.0
REAL(3/4) * 5.0
0.0
whereas
5.0 * 3 / 4
15.0 / REAL(4)
3.75
Certain arithmetical operations are prohibited because their results are not mathematically defined. For example dividing by zero, raising a negative value to a real power, and raising zero to a negative power. The Fortran Standard does not specify exactly what is to happen if one of these errors occurs: most systems issue an error message and abort the program.
Errors can also occur because numbers are stored on a computer with finite range and precision. The results of adding or multiplying two very large numbers may be outside the number range: this is called overflow. A similar effect on very large negative integers is called underflow. Most systems will issue a warning message for overflow or underflow, and may abort the program, but some processors cannot detect errors of this sort involving integer arithmetic.
Every operand (variable, array element, or function reference) used in an
expression must have a defined value at the time the expression is evaluated. Note
that variables and arrays are initially undefined unless a suitable DATA statement is
used. Expressions must not include references to any external functions with
side effects on other operands of the expression: see section 9.3 for more
details.
Arithmetic Constant Expressions
Arithmetic constant expressions can be used in PARAMETER statements and to
specify implied-DO parameters in DATA statements. All the operands in a constant
expression must be literal constants or previously defined named constants. Variables,
array elements, and function references are all prohibited. Exponentiation is only
allowed if the number is raised to an integer power.
The same rules apply to integer constant expressions but in addition the operands
must all be integer constants: such expressions can be used to specify array bounds in
type, COMMON, and DIMENSION statements, and to specify string lengths in CHARACTER
statements.
Bit-wise Logical Operations on Integers
When Fortran programs communicate directly with digital hardware it may be
necessary to carry out bit-wise logical operations on bit-patterns. Standard Fortran
does not provide any direct way of doing this, since logical variables essentially only
store one bit of information and integer variables can only be used for arithmetic.
Many systems provide, as an extension, intrinsic functions to perform bit-wise
operations on integers. The function names vary: typically they are IAND, IOR,
ISHIFT. A few systems provide allow the normal logical operators such as .AND. and
.OR. to be used with integer arguments: this is a much more radical extension
and much less satisfactory, not only because it reduces portability, but also
reduces the ability of the compiler to detect errors in normal arithmetic
expressions.
Many systems also provide format descriptors to transfer integers using octal and hexadecimal number bases: these are also non-standard.
Expressions with mixed data types should be examined carefully to ensure that the type-conversion rules have the desired effect. It does no harm to use the type conversion functions explicitly and it may make the working clearer.
Particular care is needed with the data types of literal constants. It is bad practice to use an integer constant where you really need a real constant. Although this will work in most expressions it is a serious mistake to use the wrong form of constant in the argument list of a procedure.
Long and complicated expressions which spread over several lines can be rather trying to read offer more scope for programming errors. Sometimes it is better to split the computation into several shorter equations at the expense of one or two temporary variables.
It is often tempting to try to write programs that are as efficient as possible. With
modern compilers there is little point in trying to rearrange expressions to optimise
speed. One of the few exceptions is that if an intrinsic function is provided it is
always best to use it; thus SQRT(X) is likely to be faster and more accurate than
X**0.5.
You may find that your system actually sets the whole of memory to zero initially,
except for items defined with DATA statements, but it is very bad programming
practice to rely on this.