To understand why floating-point calculations can yield different
results, you need to know how a system performs the most basic operations:
add, subtract, multiply, divide. Recall from “Inexact Result (Rounding)” that these
operations always round their results to the nearest representable
floating-point value using an algorithm specified by the rounding
mode, and that this rounding introduces a rounding error
into the result of the operation.
For example, suppose you run the following program. Two operations
that are mathematically equivalent may produce different results:
Example 3-1 Sample Program: rounderr.f
PROGRAM ROUNDERR REAL A, B, C, D, E, F PRINT *, 'Enter 4 reals:' READ *, A, B, C, D E = (A + B) * (C + D) F = (A * C) + (A * D) + (B * C) + (B * D) IF (E .EQ. F) THEN WRITE (*, 20) E, ' equals ', F ELSE WRITE (*, 20) E, ' not equal to ', F WRITE (*, *) 'Math error!' ENDIF 20 FORMAT(F, A, F) END |
Depending on the values read for A,
B, C,
and D, the program
will indeed print "Math error!", although, of
course, no error has actually occurred— only legitimate
rounding errors:
$ f90 rounderr.f rounderr.f program ROUNDERR 21 Lines Compiled $ ./a.out Enter 4 reals: 1.1 2.2 3.3 4.4 25.4100018 not equal to 25.4099998 Math error! |
This example also demonstrates a guiding principle of floating-point
programming:
Be very
careful about testing two floating-point values or expressions for
exact equality or inequality.
This principle derives from the fact that two given floating-point
values are almost never equal, even when the programmer might expect
them to be equal from a purely mathematical standpoint. The inequality
occurs because of the rounding errors incurred during the calculation
of the two values being compared.
For further discussion of this issue, see “Testing Floating-Point Values for
Equality”.