Search code examples
if-statementfortran

IF statement works in the opposite way


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:

  1. I use gfortran as a compiler
  2. the command gfortran --version returns
GNU Fortran (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
  1. I compile my programs with flags
-O2 -Wall -Wextra -fbacktrace -fcheck=all -g -o

with a level of optimization does not affect on results.

  1. my OS is Ubuntu 16.04LTS 64-bit

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.


Solution

  • 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?