Difference between revisions of "Floating point math issues"

From Geos-chem
Jump to: navigation, search
(Safe floating-point division)
Line 1: Line 1:
 +
== The pitfalls of floating point mathematics ==
 +
 +
 +
 +
 +
* [http://www.lahey.com/float.htm //The Perils of Floating Point// by Bruce M. Bush]
 +
* [http://blogs.msdn.com/ericlippert/archive/2005/01/20/fun-with-floating-point-arithmetic-part-five.aspx Fun with Floating Point Arithmetic]
 +
 
== Safe floating-point division ==
 
== Safe floating-point division ==
 +
 +
  
 
From [http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/ http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/]
 
From [http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/ http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/]
Line 17: Line 27:
 
:Thank you again,  
 
:Thank you again,  
 
:Julio.
 
:Julio.
 +
 +
We have implemented the above algorithm into GEOS-Chem.  See routine SAFE_DIV in error_mod.f:
 +
 +
      FUNCTION SAFE_DIV( N, D, ALTV ) RESULT( Q )
 +
!
 +
!******************************************************************************
 +
!  Subroutine SAFE_DIV performs "safe division", that is to prevent overflow,
 +
!  underflow, NaN, or infinity errors.  An alternate value is returned if the
 +
!  division cannot be performed. (bmy, 2/26/08)
 +
!
 +
!  For more information, see the discussion on: http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/
 +
!
 +
!  Arguments as Input:
 +
!  ============================================================================
 +
!  (1 ) N    : Numerator for the division
 +
!  (2 ) D    : Divisor for the division
 +
!  (3 ) ALTV : Alternate value to be returned if the division can't be done
 +
!
 +
!  NOTES:
 +
!******************************************************************************
 +
!
 +
      ! Arguments
 +
      REAL*8, INTENT(IN) :: N, D, ALTV
 +
     
 +
      ! Function value
 +
      REAL*8            :: Q
 +
 +
      !==================================================================
 +
      ! SAFE_DIV begins here!
 +
      !==================================================================
 +
      IF ( EXPONENT(N) - EXPONENT(D) >= MAXEXPONENT(N) .or. D==0 ) THEN
 +
          Q = ALTV
 +
      ELSE
 +
          Q = N / D
 +
      ENDIF
 +
 +
      ! Return to calling program
 +
      END FUNCTION SAFE_DIV

Revision as of 14:32, 9 April 2008

The pitfalls of floating point mathematics

Safe floating-point division

From http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/

Thank you to all that offered their suggestions for a "safe division" routine to prevent overflow. For those that are curious about the solution to the problem, I found useful to adopt a subroutine along the lines suggested by William Long:
    if(exponent(a) - exponent (b) >= maxexponent(a) .OR. b==0)Then 
     q=altv 
    else 
     q=a/b 
    endif 
The = in the >= is to take into account the case when the fractional part of a is 1.111... and that of b is 1.
It works very well.
Thank you again,
Julio.

We have implemented the above algorithm into GEOS-Chem. See routine SAFE_DIV in error_mod.f:

      FUNCTION SAFE_DIV( N, D, ALTV ) RESULT( Q )
!
!******************************************************************************
!  Subroutine SAFE_DIV performs "safe division", that is to prevent overflow,
!  underflow, NaN, or infinity errors.  An alternate value is returned if the 
!  division cannot be performed. (bmy, 2/26/08)
!
!  For more information, see the discussion on: http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/8b367f44c419fa1d/
!
!  Arguments as Input:
!  ============================================================================
!  (1 ) N    : Numerator for the division 
!  (2 ) D    : Divisor for the division
!  (3 ) ALTV : Alternate value to be returned if the division can't be done
!
!  NOTES: 
!******************************************************************************
!
      ! Arguments
      REAL*8, INTENT(IN) :: N, D, ALTV
     
      ! Function value
      REAL*8             :: Q
      !==================================================================
      ! SAFE_DIV begins here! 
      !==================================================================
      IF ( EXPONENT(N) - EXPONENT(D) >= MAXEXPONENT(N) .or. D==0 ) THEN
         Q = ALTV
      ELSE
         Q = N / D
      ENDIF
      ! Return to calling program
      END FUNCTION SAFE_DIV