Flush-to-zero in gfortran - fortran

Is there a way to force flush-to-zero of underflows in gfortran?
I can't believe this is the first time someone has asked this, but I couldn't find anything on it anywhere. Mea culpa if this is a duplicate.

You can accomplish this with recent versions of gfortran that support the Fortran 2003 IEEE modules. The standard defines two underflow modes -- gradual and abrupt. Abrupt is the one you want which sets underflow to 0 and signals the underflow floating point exception. You can test for support of controlling the underflow mode with the function ieee_support_underflow_control(X) which tests for underflow control for the kind of real X is and returns a logical true if it is supported. If supported, you can then call ieee_set_underflow_mode(.false.) to set abrupt underflow mode.
Below is a test program you can use to test underflow control support for the default real kind:
program test
use, intrinsic :: ieee_arithmetic
use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
implicit none
logical :: underflow_support, gradual, underflow
real :: fptest
integer :: i
print '(4a)', 'This file was compiled by ', &
compiler_version(), ' using the options ', &
compiler_options()
fptest = 0.0
underflow_support = ieee_support_underflow_control(fptest)
if (underflow_support) then
print *,'Underflow control supported for the default real kind'
else
stop 'no underflow control support'
end if
call ieee_set_underflow_mode(.false.)
call ieee_get_underflow_mode(gradual)
if (.not.gradual) then
print *,'Able to set abrupt underflow mode'
else
stop 'error setting underflow mode'
end if
fptest = 2e-36
do i=1,50 ! 50 iterations max
fptest = fptest * 0.5
print '(e15.10)',fptest
call ieee_get_flag(ieee_underflow,underflow)
if (underflow) print *,'Underflow exception signaling'
if (fptest == 0.0) exit
end do
end program test
Using gfortran version 5.2.0, this program outputs:
This file was compiled by GCC version 5.2.0 using the options -mtune=generic -march=x86-64 -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans
Underflow control supported for the default real kind
Able to set abrubpt underflow mode
.1000000036E-35
.5000000180E-36
.2500000090E-36
.1250000045E-36
.6250000225E-37
.3125000112E-37
.1562500056E-37
.0000000000E+00
Underflow exception signaling
The compiler option flags -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans are suggested by the gfortran 5.2 documentation to be used anytime the IEEE modules are used to ensure adherence to the standard.

A lazy way to "flush to zero" is to use to use gfortran's -funsafe-math-optimizations to:
Allow math optimizations that may violate IEEE or ISO standards
or in other words:
This mode enables optimizations that allow arbitrary reassociations and transformations with no accuracy guarantees. It also does not try to preserve the sign of zeros.
For example, small.f:
program test
real r
r=1e-40
print *,'r on next line'
print *,r
end program
Without any flags, a non-zero denormal (small) number is shown, without error:
$ gfortran -g small.f
$ ./a.out
r on next line
9.99994610E-41
Trap the denormalized number, which crashes when attempting to print the value:
$ gfortran -g -ffpe-trap=denorm small.f
$ ./a.out
r on next line
Program received signal SIGFPE: Floating-point exception - erroneous arithmetic operation.
Backtrace for this error:
#0 0x2aaaab05c26f in ???
#1 0x2aaaaac61aed in get_float_string
at ../../../libgfortran/io/write_float.def:1064
#2 0x2aaaaac6423d in list_formatted_write_scalar
at ../../../libgfortran/io/write.c:1889
#3 0x4008f1 in test
at /path/to/small.f:5
#4 0x400941 in main
at /path/to/small.f:6
Floating point exception
And added flag that flushes it to zero:
$ gfortran -g -ffpe-trap=denorm -funsafe-math-optimizations small.f
$ ./a.out
r on next line
0.00000000

Related

SEGFAULT disappears with lower optimisation level?

So, I want to help my researchers a bit with debugging Fortran programs, and for demonstration purposes I created a program that intentionally causes a segfault.
Here's the source:
program segfault
implicit none
integer :: n(10), i
integer :: ios, u
open(newunit=u, file='data.txt', status='old', action='read', iostat=ios)
if (ios /= 0) STOP "error opening file"
i = 0
do
i = i + 1
read(u, *, iostat=ios) n(i)
if (ios /= 0) exit
end do
close(u)
print*, sum(n)
end program segfault
The data.txt file contains 100 random numbers:
for i in {1..100}; do
echo $RANDOM >> data.txt;
done
When I compile this program with
gfortran -O3 -o segfault.exe segfault.f90
the resulting executable dutifully crashes. But when I compile with debugging enabled:
gfortran -O0 -g -o segfault.exe segfault.f90
Then it reads in only the first 10 values, and prints their sum. For what it's worth, -O2 causes the desired segfault, -O1 does not.
I find this deeply concerning. After all, how can I debug properly if the bug goes away when I compile with debugging symbols enabled?
Can someone explain this behaviour?
I am using GNU Fortran (MacPorts gcc5 5.3.0_1) 5.3.0
A segfault is an undefined behaviour. The program does not conform to the Fortran standard so you cannot expect any particular outcome. It can do anything at all. You cannot count with a segfault to happen, the less be deeply concerned whent it does not happen.
There are compiler checks (fcheck=) and sanitizations (-fsanitize=) available for a reason. Waiting for a segfault is not guaranteed to work. Not in Fortran, not in C, not in any similar language.
The outcome of a non-conforming program may depend on many things like placement of a variable in memory or in a register. Aligning of variables in memory, position of stack frames... You can't count with anything at all. These details obviously depend on the optimization level.
If the program accesses an array out of bounds, but the address in memory happens to be a part of memory which still belongs to the process, a segfault may not happen. It is just some bytes in memory which the process is allowed to read or write to (or both). You may be overwriting some other variable, you may be reading some garbage from some old stack frame, you may be overwriting malloc's internal book-keeping data and currupting the heap. The crash may be waiting to happen somewhere else or maybe just the numeric result of the program will be slightly wrong. Anything can happen.

Why are resulsts of silverfrost and gfortran different?

When I run my code with Silverfrost fortran, the result is -2.987531633638E-02. But with gfortran (under cygwin and ubuntu linux) it is -2.9875316336381942E-002. My code is here:
program seebeck
real*8::ss
integer::ix,i
complex,parameter::i1=(0.0,1.0)
call quad3d(0.,190.,ss)
write(*,*) "result:",ss
stop
end program seebeck
SUBROUTINE quad3d(x1,x2,ss)
REAL:: x1,x2
external f1
real*8::ss,f1
call qgausep(f1,x1,x2,ss)
return
END
SUBROUTINE qgausep(f2,a,b,ss)
external f2
REAL:: a,b
real*8::ss,f2
INTEGER j
REAL*8 dx,xm,xr,w(5),x(5)
SAVE w,x
DATA w/.2955242247,.2692667193,.2190863625,.1494513491,.0666713443/
DATA x/.1488743389,.4333953941,.6794095682,.8650633666,.9739065285/
xm=0.5*(b+a)
xr=0.5*(b-a)
ss=0
do 11 j=1,5
dx=xr*x(j)
ss=ss+w(j)*(f2(xm+dx)+f2(xm-dx))
11 continue
ss=xr*ss
return
END
function f1(t)
real*8::t,f1
f1=cos(t)/(1+exp(t))**2
end function
There is a huge difference between the two results. I cannot explain the cause of this difference as a floating point inaccuracy.
Note: My code is a draft version and has no physical meaning.
This has something to do with how different compilers handling your data assignment at line 26/27 of your code. You defined both w and x as double-precision arrays, but only initialize them with lower precision values. This will introduce some floating point inaccuracy. In fact if I pass your code through the NAG compiler (which is known to be very strict), it gives a warning:
Warning: test.f90, line 26: Low-precision data-value assigned to high-precision data-object
To confirm, you can print out the values in array w and x to see if they are different when using different compilers.

when to use iso_Fortran_env ,selected_int_kind,real(8),or -fdefault-real-8 for writing or compiling fortran code?

I have this simple code which uses DGEMM routine for matrix multiplication
program check
implicit none
real(8),dimension(2,2)::A,B,C
A(1,1)=4.5
A(1,2)=4.5
A(2,1)=4.5
A(2,2)=4.5
B(1,1)=2.5
B(1,2)=2.5
B(2,1)=2.5
B(2,2)=2.5
c=0.0
call DGEMM('n','n',2,2,2,1.00,A,2,B,2,0.00,C,2)
print *,C(1,1)
print *,C(1,2)
print *,C(2,1)
print *,C(2,2)
end program check
now when i compile this code with command
gfortran -o check check.f90 -lblas
I get some random garbage values. But when I add
-fdefault-real-8
to the compiling options I get correct values.
But since it is not a good way of variable declaration in Fortran. So I used the iso_fortran_env intrinsic module and added two lines to the code
use iso_fortran_env
real(kind=real32),dimension(2,2)::A,B,C
and compiled with
gfortran -o check check.f90 -lblas
Again I got wrong output .
Where I'm erring in this code?
I'm on 32bit linux and using GCC
DGEMM expects double precision values for ALPHA and BETA.
Without further options, you are feeding single precision floats to LAPACK - hence the garbage.
Using -fdefault-real-8 you force every float specified to be double precision by default, and DGEMM is fed correctly.
In your case, the call should be:
call DGEMM('n','n',2,2,2,1.00_8,A,2,B,2,0.00_8,C,2)
which specifies the value for alpha to be 1 as a float of kind 8, and zero of kind 8 for beta.
If you want to perform the matrix-vector product in single precision, use SGEMM.
Note that this is highly compiler-specific, you should consider using REAL32/REAL64 from the ISO_Fortran_env module instead (also for the declaration of A, B, and C).

Weird fortran numeric behavior when comparing to a constant

So I have this code in Fortran:
REAL*8 DELTA,XI,SO,S
SO=0.273333328465621
S=0.323333333556851
XI=0.01
DELTA =SO-S ! DELTA = -0.0500000050912297
IF(DELTA.GE.0.0)XI=XI/10
This code with those values always end up evaluating the IF as true and executes the XI division (i.e. XI=0.001 after. I think this is a weird behavior, but my job is to replicate that behavior in C#.
Compiled with intel fortran, no optimizations and and full debug information as part of a 32 bit DLL
Any ideas why this happens?
The following doesn't execute the IF statement. Both with gfortran and ifort.
program test_delta
double precision DELTA
DELTA = -0.0500001
IF (DELTA .GE. 0.0) then
write (*, *) "IF-statement executed"
ENDIF
end program test_delta
One change is that I added the expected "then" to the IF statement. Otherwise both compilers issued error messages.

Catch integer exceptions in Fortran

Is there a way to catch integer exceptions with gfortran or ifort like there is for catching floating point exceptions?
Consider this simple program to calculate the factorial:
program factorial
use, intrinsic :: iso_fortran_env
implicit none
integer(8) :: fac
real(REAL64) :: facR
integer,parameter :: maxOrder = 30
integer :: i
fac = 1 ; facR = 1.e0_REAL64
do i=2,maxOrder
fac=fac*i ; facR=facR*real(i,REAL64)
write(*,*) i, fac, facR
enddo ! i
end program
At some point there will be an overflow - for integer(8) as shown here, it will occur at around 21. But without the calculation using floats as a reference I couldn't tell for sure...
There is nothing in the Fortran standard that deals with integer overflow. As it stands you can't even rely on integers wrapping round when a computation exceeds the maximum value representable in the chosen kind. So, while a test such as
huge(2_8)+1 < 0_8
is likely to work with most current compilers (at least the ones I have used recently) it's not guaranteed.
I am sure that neither Intel Fortran nor gfortran provide compiler-generated run-time checks for integer overflow either. I'm not sure about other compilers but I'll be (pleasantly) surprised to learn that any of them do.
I think, therefore, that you have to proceed with your current approach.
gfortran will catch integer overflow with -ftrapv flag, see man gcc:
-ftrapv
This option generates traps for signed overflow on addition, subtraction, multiplication operations.
ifort does not seem to have that capability.