next up previous contents
Next: Character Handling and Logic Up: Professional Programmer's Guide to Previous: ConstantsVariables, and Arrays

Arithmetic

Fortran has good facilities for processing numbers. Arithmetic expressions and assignment statements can include integer, real, double precision, or complex items. Data type conversions are provided automatically when necessary; type conversions can also be performed explicitly using intrinsic functions. Other intrinsic functions are available for trigonometry, logarithms, and other useful operations.

For example, the well-known cosine formula for the third side of a triangle, given the other two sides and the angle between them is:


displaymath2931

Translated into a Fortran expression it looks like this:
SQRT(B**2 + C**2 - 2.0 * B * C * COS(ANGLEA))
which makes use of the intrinsic functions SQRT and COS. Although SQRT(X) produces the same result as X**0.5, the square-root function is simpler, faster, and probably more accurate than raising to the power of one half, which would actually be carried out using both the EXP and LOG functions.

Assignment statements evaluate an expression and assign its value to a variable (or array element). Unlike almost all other Fortran statements, they do not start with a keyword. For example:

 
      A = SQRT(B**2 + C**2 - 2.0 * B * C * COS(ANGLEA)) 
      TOTAL(N/2+1) = 0.0 
      FLUX = FLUX + 1.0

Arithmetic Expressions

An expression in its simplest form is just a single operand, such as a constant or variable. More complicated expressions combine various operands with operators, which specify the computations to be performed. For example:
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:
displaymath2933
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.

General Rules

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:

The rules for forming more complicated arithmetic expressions are as follows. An arithmetic expression can have any of the following forms:
tabular545
where the arith-op can be any of these operators:
tabular558

The effect of these rules is that an expression consists of a string of operands separated by operators and, optionally, a plus or minus at the start. A leading plus sign has no effect; a leading minus sign negates the value of the expression.

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:

  1. sub-expressions in parentheses
  2. function references
  3. exponentiation, i.e. raising to a power
  4. multiplication and division
  5. addition, subtraction, or negation.

Within each of these groups evaluation proceeds from left to right, except that exponentiations are evaluated from right to left. Thus: 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.

Data Type Conversions

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:

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:

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:

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
D may end up with a value such as 0.3333333432674408... which is no closer to the value of one third than R was originally.

Integer Division

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:

The combination of the two preceding rules may have unexpected effects, for example:

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:

whereas

Restrictions

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.

Guidelines

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.

Arithmetic Intrinsic Functions

Intrinsic functions are supplied automatically by the system and can be used in expressions in any program unit. A description of their special properties appears in section 9.1.

Many of the arithmetic intrinsic functions have generic names: that is they can be used with several different types of arguments. The SQRT function, for example, can be used with a real, double precision, or complex argument. The Fortran system automatically selects the correct specific function for the job: SQRT, DSQRT, or CSQRT. These specific names can be ignored in almost all circumstances, and are listed only in the appendix. In most cases the data type of the function is the same as that of its argument but there are a few obvious exceptions such as the type conversion functions.

In the descriptions below, the number and data type of the arguments of each intrinsic function are indicated by a letter: I = integer, R = real, D = double precision, X = complex.

An asterisk on the left indicates that the result has the same data type as the arguments. Note that if multiple arguments are permitted they must all have the same data type. Thus I = NINT(RD) indicates that the NINT function can take a single real or double precision argument but its result is always integer, whereas * = ANINT(RD) indicates that the result has the same type (real or double precision) as the argument.

Trignometric Functions

The functions in this group can all be used on real or double precision arguments, and SIN and COS can also be used on complex numbers. In every case the result has the same data type as the argument.


tabular607

Note that the arguments of SIN, COS, and TAN must be angles measured in radians (not degrees). They can be used on angles of any size, positive or negative, but if the magnitude is very large the accuracy of the result will be reduced. Similarly all the inverse trigonometric functions deliver a result in radians; the argument of ASIN and ACOS must be in the range -1 to +1. The ATAN2 function can be useful in resolving a result into the correct quadrant of the circle, thus:
ATAN(0.5) = 0.4636476
ATAN2(2.0,4.0) = 0.4636476
ATAN2(-2.0,-4.0) = -2.677945 ( = 0.4636476 - tex2html_wrap_inline2929).

Other Transcendental Functions


tabular622

Note that LOG10, which may be useful to compute decibel ratios etc., is the only one of this group which cannot be used on a complex argument.

Type Conversion Functions

These functions can be used to convert from any of the four arithmetic data types to any of the others. They are used automatically whenever mixed data types are encountered in arithmetic expressions and assignments.


tabular631

The integer conversion of INT rounds towards zero; if you need to round to the nearest integer use the NINT function (described below). The CMPLX function produces a value with a zero imaginary component unless it is used with two arguments (or one which is already complex). It is important to realise that many conversions lose information: in particular a double precision value is likely to lose significant digits if converted to any other data type.

Minimum and Maximum

The MIN and MAX functions are unique in being able to take any number of arguments from two upwards; the result has the same data type as the arguments.


tabular640

These two functions can, of course, be combined to limit a value to a certain range. For example, to limit a value TEMPER to the range 32 to 212 you can use an expression such as:
MAX(32.0, MIN(TEMPER, 212.0))
Note that the minimum of the range is an argument of the MAX function and vice-versa.

To find the largest (or smallest) element of a large array it is necessary use a loop.

 
*Find largest value in array T of N elements:  
      TOP = T(1) 
      DO 25,I = 2,N 
         TOP = MAX(T(I), TOP) 
25    CONTINUE 
*TOP now contains the largest element of T.

Other Functions


tabular647

The NINT and ANINT functions round upwards if the fractional part of the argument is 0.5 or more, whereas INT and AINT always round towards zero. Thus:
INT(+3.5) = 3 NINT(+3.5) = 4
INT(-3.5) = -3 NINT(-3.5) = -4
The fractional part of a floating point number, X, can easily be found either by:
X - AINT(X)
or
MOD(X, 1.0)
In either case, if X is negative the result will also be negative. The ABS function can always be used to alter the sign if required.

The MOD function has other uses. For example it can find the day of the week from an absolute day count such as Modified Julian Date (MJD):
MOD(MJD,7)
has a value between 0 and 6 for days from Wednesday to Tuesday. Similarly if you use the ATAN2 function but want the result to lie in the range 0 to 2ã (rather than -ã to +ã) then, assuming the value of TWOPI is suitably defined, the required expression is:
MOD(ATAN2(X,Y) + TWOPI, TWOPI)

Arithmetic Assignment Statements

An arithmetic assignment statement has the form:
arithmetic-var = arithmetic-expression
where arithmetic-var can be an arithmetic variable or array element. For example, the following assignment statement is valid provided that N, K, and ANGLE are all defined values:
IMAGE(N/2+1,3*K-1) = SIN(ANGLE)**2 + 1.0
If the object on the left has a different data type from that of the expression on the right then a data type conversion is applied automatically. The type conversion function (INT, REAL, DBLE, or CMPLX) is selected to match the object on the left. Note that many type conversions lose information. If the object on the left is an array element, its subscripts can be arbitrary integer expressions, but all the operands in these expressions must be defined before the statement is executed and each must be in the range declared for the corresponding subscript of the array.

Remember with an integer item on the left and an expression of one of the floating-point types, the INT function is invoked: if the NINT function is really needed then it must be used explicitly to convert the value of the expression.


next up previous contents
Next: Character Handling and Logic Up: Professional Programmer's Guide to Previous: ConstantsVariables, and Arrays

Clive Page
Tue Feb 27 11:14:41 GMT 2001