I have a subroutine ran_init ( length )
, in which one IF
statement works incorrectly.
The code below is a highly simplified version of my original code:
MODULE ran_state
USE nrtype
IMPLICIT NONE
INTEGER, PARAMETER :: K4B = SELECTED_INT_KIND ( 9 )
INTEGER ( K4B ), PARAMETER :: hg = HUGE ( 1_K4B ), hgm = -hg, hgng = hgm - 1
INTEGER ( K4B ), SAVE :: lenran = 0
CONTAINS
SUBROUTINE ran_init ( length )
USE nrtype; USE nrutil, ONLY: nrerror
IMPLICIT NONE
INTEGER ( K4B ), INTENT ( IN ) :: length
INTEGER ( K4B ) :: hgt
IF ( length < lenran ) RETURN
hgt = hg
PRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng
IF ( hgt + 1 .NE. hgng ) CALL nrerror ( 'ran_init: arith assump 3 fails' )
END SUBROUTINE
END MODULE ran_state
This code returns the result:
2147483647 -2147483648 -2147483648 0
nrerror: ran_init: arith assump 3 fails
STOP program terminated by nrerror
It is seen that values hgt + 1
and hgng
are equal to one another, but at the IF
statement these values are interpreted as unequal.
Why this can happen?
UPD №1 Some technical details:
gfortran
as a compilergfortran --version
returnsGNU Fortran (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
-O2 -Wall -Wextra -fbacktrace -fcheck=all -g -o
with a level of optimization does not affect on results.
UPD №2
I don't know WHY, but if one create a new variable, say, hgtp
of type INTEGER ( K4B )
and replace lines
hgt = hg
PRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng
IF ( hgt + 1 .NE. hgng ) CALL nrerror ( 'ran_init: arith assump 3 fails' )
with lines
hgt = hg
hgtp = hgt + 1
PRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng
IF ( hgtp .NE. hgng ) CALL nrerror ( 'ran_init: arith assump 3 fails' )
the IF-statement begins to interpret the condition hgtp .NE. hgng
as true.
MODULE ran_state
IMPLICIT NONE
INTEGER, PARAMETER :: K4B = SELECTED_INT_KIND ( 9 )
INTEGER ( K4B ), PARAMETER :: hg = HUGE ( 1_K4B ), hgm = -hg, hgng = hgm - 1
INTEGER ( K4B ), SAVE :: lenran = 0
CONTAINS
SUBROUTINE ran_init ( length )
INTEGER ( K4B ), INTENT ( IN ) :: length
INTEGER ( K4B ) :: hgt, temp
hgt = hg
PRINT *, hgt, hgt + 1, hgng, hgt + 1 - hgng
temp = hgt + 1
IF ( temp /= hgng ) print *, 'temp fails'
IF ( hgt + 1 /= hgng ) print *, '3 fails'
END SUBROUTINE
END MODULE ran_state
program main
use ran_state
call ran_init( 0_K4B )
end program main
With ifort (intel fortran), default flags:
2147483647 -2147483648 -2147483648 0
With gfortran, default flags:
2147483647 -2147483648 -2147483648 0
3 fails
Something odd about gfortran?