USAGE OF CONSTANTS IN FLOATING POINT EXPRESSIONS
IN THE PROGRAM XBEACH
Willem Vermin, SARA, 2008-07-09
Here follow some remarks with regard to the use of constants
in Fortran.
The program xbeach uses everywhere double precision, and some
coding practices are required to be sure that double precision
is maintained.
Examples:
Below x and y are double precision (= real*8) variables,
n is integer.
The constant 1.3 is single precision. If used in an double
precision expression, this constant will be promoted to double,
but the value will be different from the double precision
constant 1.3d0.
Try the following program:
program a
implicit none
if (1.3 .eq. 1.3d0) then
print *,'equal'
else
print *,'not equal, difference is',1.3-1.3d0
endif
end
So, in general one should specify floating point constants as
1.3d0.
Also, one should code
y = max(x,1.3d0)
and not
y = max(x,1.3) ! not good
Apart from the inaccuracy the latter construct involves, not
all compilers have a MAX instrinsic with one argument
double and the other argument single.
In the following example:
y = x*atan(1.0) ! wrong
atan(1.0) gives a single precision result, because the single
precision argument. This result will be promoted to double,
but the precision is still that of a single precision floating
point number.
y = x*atan(1.0d0) ! ok
gives the desired result.
INTEGER CONSTANTS
(in the atan(1.0) example, the constant 1.0 is not 'really' an integer,
but 'integer by accident'. ATAN always expacts a floating point argument)
In general, it is not necessary to specify integer constants
as double, like:
y = 2.0d0 * x ! is ok, but see later
This code will yield the expected result, but a more readable
code like
y = 2 * x ! is ok
will also give the desired result, and could be even more efficient.
Promotion of a integer constant to double, if necessary, will
be done at compile time. In the above example the compiler could
decide to increase the exponent of x by one in stead of performing
a floating point operation.
Also in expressions like:
y = 0
y = x + 1
y = x / 4
it is not necessary to specify double precision constants, especially
in the case of a division. A floating point division is expensive. Using
integer values for the divisor, the compiler can decide to subtract
2 from the exponent in this case.
Especially in expressions involving the ** operator, it is better
to use
y = x**2 ! ok
in stead of
y = x**2.0d0 ! maybe inefficient
In the latter case, the compiler could generate code to do a double
precision exponentiation (involving the evaluation of a exp and a log),
wheras a simple multiplication suffices. Since long, compilers know how
to efficiently perform an exponentiation with an integer exponent.
Of course, constructs like
n = 5
y = n/4 !wrong
in general do not give the expected result: in this case y would
get the value 1.0d0, and not 1.2d0.
somewhat better is
y = real(n)/4 ! better, but not good
because the intrinsic REAL yields a single precision floating
point value. Better is
y = dble(n)/4 ! ok
This seems trivial, but also in expressions like
y = x*(n/4) ! wrong
n/4 is evaluated on its own, and the result is converted to double.
Good is:
y = x*(dble(n)/4) ! good
or
y = x*n/4 ! also good
(n is promoted to double before the multiplication with x.
or
y = x*dble(n)/4 ! the best