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.

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