Compiler options to trap floating point errors

I am going to tweet about compiler options that trap floating point errors. There are

gfortran -ffpe-trap=invalid,zero,overflow
ifort -fpe0

What are the analogous options for other compilers?

program to generate NaN
program test_nan
implicit none
real :: a, b, c
a = 0.0
b = 0.0
print*,"a, b=",a,b
print*,"computing c = a/b"
c = a/b
print*,"c=",c
end program test_nan
! output with gfortran trap_nan.f90
!  a, b=   0.00000000       0.00000000    
!  computing c = a/b
!  c=              NaN
!
! output with gfortran -ffpe-trap=invalid trap_nan.f90
!  a, b=   0.00000000       0.00000000    
!  computing c = a/b
! Program received signal SIGFPE: Floating-point exception - 
! erroneous arithmetic operation.
!
! output for ifort -fpe0 trap_nan.f90
!  a, b=  0.0000000E+00  0.0000000E+00
!  computing c = a/b
! forrtl: error (65): floating invalid
program to generate overflow
program test_overflow
real :: x
x = huge(x)
x = x**2
print*,x
end program test_overflow
! output with gfortran trap_overflow.f90
! Infinity
!
! output with gfortran -ffpe-trap=overflow trap_overflow.f90
! Program received signal SIGFPE: Floating-point exception 
! - erroneous arithmetic operation.
!
! output for ifort -fpe0 trap_overflow.f90
! forrtl: error (72): floating overflow
4 Likes

For GFortran I also recommend:

  • -finit-real=snan -finit-integer=-99999999 so that if you don’t initialize a real variable, and happen to use it, it will trigger the trap.
  • -fbacktrace which prints a stacktrace when the runtime trap happens

For the integer variable it will not trap, but at least it is initialized to such a value that it will break your code typically and you’ll see it (whether using it as an array index or in some other way).

4 Likes

This is a great topic to tweet! Thank you for doing it.

Sorry if I missed something: is it possible to link the tweets to copiable code snippets (e.g., gists)? I believe that many readers of the tweets would like to have a quick try of the code. Even better if they can be linked to some online compiling/testing platforms.

Many thanks!

The FortranTip GitHub repo has an index of tweets and the codes.

1 Like

That’s great! Is there some (automatic) way to link each of the tweets to the corresponding piece of code? I understand this will take some work. The current situation is already quite convenient. Thank you.

Given how prevalent is the computing using IEEE floating-point arithmetic and the duration since the commonly used Fortran processors have started supporting IEEE facilities introduced in the language starting Fortran 2003 nearly 18 years ago, posting about compiler options for the matter at hand seems a step backward.

I suggest looking at IEEE intrinsic modules instead, especially IEEE_EXCEPTIONS.

Consider the code in the original post where the invalid floating-point instruction does not get trapped and thus no run-time exception gets raised.

   real :: a, b, c
   a = 0.0
   b = 0.0
   print*,"a, b=",a,b
   print*,"computing c = a/b"
   c = a/b
   print*,"c=",c
end

C:\temp>ifort /standard-semantics p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation. All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
a, b= 0.000000 0.000000
computing c = a/b
c= NaN

C:\temp>

With suitable use of SET_HALTING_MODE intrinsic procedure whose interface is provided in IEEE_EXCEPTIONS intrinsic module, one can achieve better control of run-time exception handling and trapping:

   use :: ieee_exceptions, only : IEEE_SET_HALTING_MODE, IEEE_INVALID
   real :: a, b, c
! example of naive handling a la -fpe0 or -ffpe-trap options
   call ieee_set_halting_mode( IEEE_INVALID, halting=.true. )
   a = 0.0
   b = 0.0
   print*,"a, b=",a,b
   print*,"computing c = a/b"
   c = a/b
   print*,"c=",c
end

C:\temp>ifort /standard-semantics p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation. All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
a, b= 0.000000 0.000000
computing c = a/b
forrtl: error (65): floating invalid
Image PC Routine Line Source
p.exe 00007FF65E751168 Unknown Unknown Unknown
p.exe 00007FF65E7A173E Unknown Unknown Unknown
p.exe 00007FF65E7A1AC0 Unknown Unknown Unknown
KERNEL32.DLL 00007FFCEDF77034 Unknown Unknown Unknown
ntdll.dll 00007FFCEE3E2651 Unknown Unknown Unknown

C:\temp>

3 Likes

But now, the language standard does not recognize as such anything with tracing back the source of the error. So here a pursuit of a compiler option makes sense.

And by the way, the option will be -traceback (/traceback on Windows OS) with the IFORT compiler (e,g, as part of Intel oneAPI)

1 Like

This is an excellent suggestion. I hadn’t thought of it, but will use it in my ongoing work debugging some old code. Thanks.

Thanks. I tweeted

Call ieee_set_halting_mode() of F2003 module ieee_exceptions to set the floating point conditions (NaN, overflow, underflow, divide-by-zero, inexact) that will halt a program. Compiler options include
gfortran -ffpe-trap=invalid
ifort -fpe0.

! A reference is https://www.nag.com/nagware/np/r70_doc/ieee_arithmetic.html
program test_ieee_exceptions
use :: ieee_exceptions, only: ieee_set_halting_mode, ieee_invalid, &
       ieee_overflow, ieee_underflow, ieee_divide_by_zero, ieee_inexact
implicit none
real :: a, b, c, d, e, f, g
logical, parameter :: halt_program = .true.
call ieee_set_halting_mode([ieee_divide_by_zero, ieee_underflow, &
     ieee_overflow, ieee_invalid],halting=halt_program)
! causes halt if divide_by_zero, underflow, overflow, or NaN conditions occur
! remove element from array constructor to have program continue with that condition
f = 1.0
print*,"computing 1.0/0.0"
print*,f/0.0
e = tiny(e)
print*,"tiny =",e,", computing tiny/10"
print*,e/10
d = huge(d)
print*,"huge =",d,", computing huge**2"
print*,d**2
a = 0.0
b = 0.0
print*,"a, b=",a,b
print*,"computing c = a/b"
c = a/b
print*,"c=",c
! since floating point roundoff is ubiquitous, probably
! do not want the following mode
call ieee_set_halting_mode(ieee_inexact, halting=halt_program)
print*,"computing 2.0/3.0"
g = 2.0/3.0
print*,"2.0/3.0 =",g
end program test_ieee_exceptions
! output on Windows with ifort -traceback ieee_exceptions.f90
!  computing 1.0/0.0
! forrtl: error (73): floating divide by zero
! Image              PC                Routine            Line        Source             
! ieee_exceptions.e  00007FF6EBBF112A  MAIN__                     14  ieee_exceptions.f90