An integer overflow problem

The following program compiled with gfortran, ifort and ifx is computing correctly 2**31-1 when n is declared as int32 (although I would not have been surprised if it had failed):

program main
  use iso_fortran_env
  integer(int32) :: n
  integer :: i

  i = 31
  n = 2**i - 1
  print *, n, kind(n)
end program main
$ gfortran main.f90 && ./a.out
  2147483647           4
$ ifort main.f90 && ./a.out
  2147483647           4
$ ifx main.f90 && ./a.out
  2147483647           4

but surprisingly with integer(int64) :: n, there is an integer overflow with ifort 2021.5.0 (Ubuntu 21.10):

$ gfortran main.f90 && ./a.out
           2147483647           8
$ ifort main.f90 && ./a.out
           -2147483649           8
$ ifx main.f90 && ./a.out
            2147483647           8
1 Like

The calculation is done with an integer of 4 bytes, so the outcome of 2**31 is too big. Apparently there is something odd going on though.

Can you compile your example with warnings, please? Could be interesting…

1 Like

gfortran -Wall -Wextra main.f90 prints no warning in both cases.
Same with ifort -warn all main.f90.

And if I don’t use the i variable and write directly 2**31 - 1, only gfortran (version 11.2.0) complains:

$ gfortran main.f90 && ./a.out
main.f90:7:7:

    7 |   n = 2**31 - 1
      |       1
Error: Result of exponentiation at (1) exceeds the range of INTEGER(4)
1 Like
n = int(2_8**31 - 1)
1 Like

With n = 2_8**i - 1, ifort is computing correctly in the int64 case.

You can achieve this without int64:

n = -((-2)**31 +1)
1 Like

Compare following:

program main
  use iso_fortran_env
  integer(int32) :: n
  integer :: i

  i = 31
  n = 2**i 
  print *, n, kind(n)   ! ==>  -2147483648  4
  n = n - 1
  print *, n, kind(n)   ! ==>   2147483647  4
end program main

It seems double overflow occurring here and the result is expected.

In 64-bit version it is really odd, looks like ifort treats the first result (2**31) as 64-bit value of -2147483648, subtracting 1 gives -2147483649

2 Likes

Interesting, it explains the results with int32.

With int64, the three compilers now give the same result, but with an overflow on 2**31:

$ gfortran main.f90 && ./a.out
          -2147483648           8
          -2147483649           8
$ ifort main.f90 && ./a.out
           -2147483648           8
           -2147483649           8
$ ifx main.f90 && ./a.out
           -2147483648           8
           -2147483649           8

Which is perfectly okay

1 Like