Understanding rounding operations in XL Fortran can help you get predictable, consistent results. It can also help you to make informed decisions when you have to make tradeoffs between speed and accuracy.
In general, floating-point results from XL Fortran programs are more accurate than those from other implementations because of MAF operations and the higher precision used for intermediate results. If identical results are more important to you than the extra precision and performance of the XL Fortran defaults, read Duplicating the Floating-Point Results of Other Systems.
To change the rounding mode in a program, you can call the fpsets and fpgets routines, which use an array of logicals named fpstat, defined in the include files /usr/include/fpdt.h and /usr/include/fpdc.h. The fpstat array elements correspond to the bits in the floating-point status and control register.
For floating-point rounding control, the array elements
fpstat(fprn1) and fpstat(fprn2) are set as specified in the
Table 19. Rounding-Mode Bits to Use with fpsets and fpgets
|fpstat(fprn1)||fpstat(fprn2)||Rounding Mode Enabled|
|.true.||.true.||Round towards -infinity.|
|.true.||.false.||Round towards +infinity.|
|.false.||.true.||Round towards zero.|
|.false.||.false.||Round to nearest.|
program fptest include 'fpdc.h' print *, 'Before test: 2.0 / 3.0 = ', 2.0 / 3.0 print *, ' -2.0 / 3.0 = ', -2.0 / 3.0 call fpgets( fpstat ) ! Get current register values. fpstat(fprn1) = .TRUE. ! These 2 lines mean round towards fpstat(fprn2) = .FALSE. ! +INFINITY. call fpsets( fpstat ) r = 2.0 / 3.0 print *, 'Round towards +INFINITY: 2.0 / 3.0= ', r call fpgets( fpstat ) ! Get current register values. fpstat(fprn1) = .TRUE. ! These 2 lines mean round towards fpstat(fprn2) = .TRUE. ! -INFINITY. call fpsets( fpstat ) r = -2.0 / 3.0 print *, 'Round towards -INFINITY: -2.0 / 3.0= ', r end ! This block data program unit initializes the fpstat array, and so on. block data include 'fpdc.h' include 'fpdt.h' end
XL Fortran also provides several procedures that allow you to control the floating-point status and control register of the processor directly. These procedures are more efficient than the fpsets and fpgets subroutines because they are mapped into inlined machine instructions that manipulate the floating-point status and control register (fpscr) directly.
XL Fortran supplies the procedure, get_round_mode(), which is available in the xlf_fp_util module. This procedure returns the current floating-point rounding mode.
USE XLF_FP_UTIL INTEGER(FPSCR_KIND) MODE MODE=get_round_mode() IF (MODE .EQ. FP_RND_RZ) THEN ! ... END IF
There are several strategies for handling rounding errors and other unexpected, slight differences in calculational results. You may want to consider one or more of the following strategies:
Rounding operations, especially in loops, reduce code performance and may have a negative effect on the precision of computations. Consider using double-precision variables instead of single-precision variables when you store the temporary results of double-precision calculations, and delay rounding operations until the final result is computed. You can also specify the hssngl suboption of -qfloat instead of converting a stored single-precision result back to double-precision. This suboption preserves computed double-precision results so that they can be used again later.
The compiler evaluates floating-point expressions during compilation when it can, so that the resulting program does not run more slowly due to unnecessary run-time calculations. However, the results of the compiler's evaluation might not match exactly the results of the run-time calculation. To delay these calculations until run time, specify the nofold suboption of the -qfloat option.
The results may still not be identical; for example, calculations in DATA and PARAMETER statements are still performed at compile time.
The differences in results due to fold or nofold are greatest for programs that perform extended-precision calculations or are compiled with the -O option or both.
You can change the rounding mode from its default setting of round-to-nearest by calling the fpsets subroutine inside a program. If you do so, you must be careful that all rounding operations for the program use the same mode:
For example, you might compile a program like the one in Selecting the Rounding Mode with this command if the program consistently uses round-to-plus-infinity mode:
xlf95 -qieee=plus -qfloat=rrm changes_rounding_mode.f