« previous next»

2.5    Precision

    One of the biggest concerns with using real quantities is precision.  Often real numbers cannot be stored exactly in the computer's memory, and this can lead to error when looking at real results.  The default precision for real data is known as single-precision.  Although the exact accuracy is compiler dependent, in general single precision for real data is typically about seven decimal digits and the range around -1038 to 1038.   For some applications higher precision is desired. All compilers have at least two kinds of real types, single-precision and double-precision.  Single precision is the default for any real number, but double precision can be indicated for values in many ways.
    Exponentials declared with D rather than E for the exponent are immediately of kind double-precision real by default.  For example:

    3.0D1

is given double-precision because D is used to indicate the exponent.  If an E was used the value would have the default accuracy of single-precision.

    Real declaration statements can be used to indicate the precision for parameters as follows:

    REAL(KIND = kind_number)  :: vars

Numbers that indicate to the compiler what precision of real number is being used are known as kind numbers.  Just as the exact accuracy of single and double precision varies from one compiler to the next, so do the kind numbers associated with them.  Typically if single will be KIND = 1 and double KIND = 2.  Another common option is single-precision KIND = 4 and double-precision KIND = 8.  So this brings us naturally to the question of how we can determine the kind numbers for our compiler.  Useful for this purpose is the function SELECTED_REAL_KIND.  Its general form is:

    SELECTED REAL KIND (p, r)

Where p is the precision desired (number of digits needed to the right of the decimal point) and r is the range (-10r to 10r).  p and r are both integer values.  This function will return a kind type parameter with at least precision of p and range rp and r do not have to both be specified.  Only one is sufficient for selecting a kind number.

    Another intrinsic function, KIND (x), can be used to find kind numbers for particular expressions.  For example:

    KIND (4.13)

will return the kind number for single-precision, while

    KIND (1.0D1)

will return the kind number for double precision because D implies a double-precision exponent.

    Another concern is writing your programs so they can be carried from one compiler to the next without the need for reprogramming compiler dependent statements.  In choosing kind numbers there are ways to make your codes "portable" (meaning they can be executed on any Fortran 90 compiler without compiler dependent errors).  You can do this by declaring a kind number for single and double-precision in the declaration section of your program.

    INTEGER, PARAMETER  ::  double = SELECTED_REAL_KIND (13)

    REAL (KIND = double) :: A, B

In this series of commands the parameter double has been assigned the kind value for double-precision (p = 13 will require double precision).  The kind for A and B has been assigned the number for double-precision.  Code written with such declarations are portable without corrections.

    An underscore followed by a kind number appended to a constant is an indicator of the kind of that constant.  In general:

    constant_kindnumber

For example:

    3.453_2

The number 3.453 is of kind number 2.  Again, for portability it is better to use parameters rather than actual numerical values for appending your constants.

    3.453_double

Now 3.453 has the kind number double.  If appropriate statements are made in the declaration section (as previously discussed) then double will be the kind number for double-precision regardless of the compiler used.

If double-precision is required for the output of an expression then all variables and constants in that expression should be of double-precision kind.  If constants are single-precision and other values double-precision the result will not be as accurate.  For example:

    PROGRAM accuracy

    IMPLICIT NONE

    INTEGER, PARAMETER  ::  double = SELECTED_REAL_KIND (13)
    REAL (KIND = double) :: A, B, C

    A = 2.0_double
    B = 0.1 * A
    C = 0.1_double * A

    PRINT *, B
    PRINT *, C

    END PROGRAM

Depending on your system the output for your program could give the following:

    0.2000000029802322
    0.2000000000000000

Although the output for B and C should be the same, they are not due to the accuracy of the multiplicative constant (0.1).  The precision for C is double-precision because both the constant (as indicated by the underscore (_) followed by double kind number) and the value for A have double precision.  However, B has lost precision because the constant used to multiply A has only default single precision.  Accuracy has been lost.  Note that the value for B will vary for compiler, but will not be as accurate as C. Similarly the commands

a = 0.745

b = 0.745D0

may result in a and b having different values because 0.745 is of single precision but a, b and 0.745D0 are of double precision. Thus variable a, could finally have a value like 0.7450000035810196.

« previous next»