Home > Software engineering >  IF statement works in the opposite way
IF statement works in the opposite way

Time:08-19

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.

CodePudding user response:

You're running into integer overflow, which is an undefined operation in Fortran. Meaning that the Fortran processor (compiler and runtime) is allowed to do anything it likes with it, like doing some more or less random calculation, abort the compilation with an error message, abort the program at runtime with an error message, or launch the rockets to start WWIII.

What it means that you cannot rely on some particular behavior if integer overflow happens. Generally compilers will optimize the code to be as fast as possible, assuming no overflow occurs (because then it's undefined behavior and it's the responsibility of the programmer to ensure that the program doesn't get into such a state).

Further, there's two kinds overflow here:

  • hgt 1 is kind of obvious, since hgt is equal to HUGE().
  • hgm - 1 is also an overflow. It's not an overflow on hardware that uses two's complement representation of integers (which is, practically speaking, all hardware out there these days outside maybe some museum piece), however the Fortran model numbers are symmetrical so in the Fortran standard it's an overflow, and again, all bets are off.

(The above assuming you're running on a system where the default integer has the same kind as K4B which should be most systems out there these days unless you're using some -fdefault-integer-8 or such options)

CodePudding user response:

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?

  • Related