# Handling integer overflow

To handle integer overflow in a multiplication, you could do the multiplication in floating point arithmetic, check if it exceeds `huge(i)`, and return a sentinel value if it does, as done in the code below. The user should test if the result equals the sentinel. Is that a good approach? A related 2017 thread from the Intel Fortran forum was How best to handle integer overflow situations?

``````module product_mod
implicit none
private
public :: prod, dp
integer, parameter :: dp = kind(1.0d0)
contains
elemental function prod(i, j, bad) result(ij)
! return the product of i and j, unless it overflows, in which case return bad
integer, intent(in) :: i, j, bad
integer             :: ij
real(kind=dp)       :: xij
xij = real(i, kind=dp) * real(j, kind=dp)
if (abs(xij) > huge(i)) then
else
ij = i*j
end if
end function prod
end module product_mod
!
program xproduct
use product_mod, only: prod, dp
implicit none
integer :: i, isq, imin
imin = int(sqrt(real(huge(i), kind=dp)))
print*,"huge(i) =", huge(i)
print "(/,*(a20))", "i", "prod(i, i, -1)", "i*i"
do i=imin, imin+2
isq = i*i
print "(*(i20))", i, prod(i, i, -1), isq
end do
end program xproduct
``````

output:

`````` huge(i) =  2147483647

i      prod(i, i, -1)                 i*i
46340          2147395600          2147395600
46341                  -1         -2147479015
46342                  -1         -2147386332
``````
2 Likes

Nice question I would start by asking for an integer kind that can store large numbers, with `selected_int_kind()`. Then, we could do the multiplication and check if the result is finite with `ieee_is_finite()`. Now, what if the largest kind available was not enough? Well, then I would probably start translating Java’s BigInteger in Fortran, or look for a library that can handle arbitrary precision arithmetic.

I think there are several approaches that can be taken, depending on how much effort the programmer is willing to expend. If the default integer kind is `int32` and if `int64` is available, then as mentioned above the result can be computed and tested with `int64`, and then converted to `int32` if successful. If only one integer kind is available, or if the calculations are being done in the longest kind already, then the following approach can be used.

``````integer(ik) :: i, j, ij, bigj
bigj = huge(ij) / abs(i)
if ( abs(j) > bigj ) then
istat = overflow_code
else
ij = i * j
istat = normal_code
endif
``````

This obviously costs an integer division in addition to the multiplication, so it is expensive. I also would recommend using a subroutine interface rather than a function interface for this operation so that the `istat` value can be tested in a straightforward way in the calling program. There is also the potential problem of false negative when the product is `-huge(ij)-1`. That is a representable number, but it would be falsely flagged as an overflow in the above test (it does overflow the fortran model number range). Those special cases could also be tested, but with even more effort.

We have used procedures essentially identical to what you describe but we did use them as functions but they stopped the program if overflow was detected so there was no flag being returned.

We did something different for the largest kind on the Cray because (for reasons I do not remember at the moment) the cost of the division was onerous but can not access the archives to see if notes remain on what the alternative was.

But as stated, just considering commonly used kinds, our favorite little prime huge(0) has the condition huge(0_int32)**2 < huge(0_int64) , so all products of two 32-bit values are safe.

The alternative to division involved checking if both values had an absolute value < sqrt(huge(0)) and just proceeding and then went ahead and did the multiplication and did some checks on the sign bit I think, but
I think it was only safe for a particular programming environment.

@FortranFan comments in that thread that when multiplying two large enough integer numbers a wrap around the `integer(4)` representable number line can occur. My way to go is similar to what is proposed in the post and OP: since all `integer(4)` representable numbers can be represented as `real(8)` variables exactly, I keep a double precision “control” variable and compare the results between integer and real multiplications. For example, this program calculates 15!=1307674368000, which wraps around the number line several times,

``````program test_integer_overflow

implicit none

integer, parameter :: dp = 8

integer :: i
integer :: a(15) = [(i, i = 1, size(a))]

real(dp) :: tst = 1.0_dp

do i = 1, size(a)
tst = tst*real(a(i), dp)
enddo
print*, "Multiplication with reals: ", tst, "."
print*, "Integer conversion: ", int(tst), "."
print*, "Multiplication with integers, ", product(a), "."
print*, "Absolute difference:", abs(tst - real(product(a), dp)), "."
print*, "Epsilon (double precision):", epsilon(1.0_dp), "."
print*, "Overflow?", (abs(tst - real(product(a), dp))>epsilon(1.0_dp)), "."

end program test_integer_overflow
``````

Output:

`````` Multiplication with reals:    1307674368000.0000      .
Integer conversion:  -2147483648 .
Multiplication with integers,   2004310016 .
Absolute difference:   1305670057984.0000      .
Epsilon (double precision):   2.2204460492503131E-016 .
Overflow? T .
``````

There are some situations where the programmer cannot recover from the overflow and that is the only option. In other cases, the return status code allows the programmer to use alternative algorithms, or to modify the algorithm somehow, and still obtain the final solution despite the initial integer overflow.

One way to handle both situations is to let the `istat` dummy variable have the `optional` attribute. If it is present, then the `overflow_code` value is returned and execution continues. If it is not present, then the program can abort at that time (e.g. with `error stop`). Thus both situations are handled in a straightforward way with a single subroutine.

Regarding whether to use `int64` or `real64` to compute the results in extended precision, modern fortran (since f2008 I think) has required an extended integer kind with at least 18 decimal digits. All compilers I use provide `int64` to satisfy this requirement, although a longer integer type would also be allowed. Thus the integer product can be computed exactly with this extended integer kind and the programmer can depend on its support by the compiler in a portable way. Before f2008, only the default integer kind was required to exist, typically `int32`, so relying on compiler support of any extended integer kind was risky. In contrast, double precision was required going back to f77 (at least in the full implementation), so within these earlier standards that was the most reliable and portable way to compute the extended precision intermediate; even if it was typically only 53-bits of mantissa, the overflow of 31 bits could still be detected reliably.