Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29276 Discussions

Any way to FORCE integer overflow checking ?

WSinc
New Contributor I
1,547 Views

I have a program that gives mysterious results when the sizes of the integers get to be above a certain threshold.

Finding where the overflow occurs is proving to be very elusive, since no trap is generated.

Is this something that's a integral part of the INTEL processor?

For example, could that be checked at the machine code level?

Example: check if A*B is correct - -  (Fortran source)

c=a*b

if(a>0 .and. b<0 .and. c <0) .or. &

(a<0 .and. b<0 .and. c <0) .or. &

(a>0 .and. b<0 .and. c >0) .or. &

(a<0 .and. b>0 .and. c >0) then

   etc. etc. 

But this is extremely awkward putting that everywhere in the code.

And it does not always catch a bad result. You can have a wrong answer with the correct sign.

another approach is do write a special routine to do basic add, multiply, sub, etc.

Notice that using higher precision integers does NOT guarantee you will get accurate results -

 

If A and B are both int8, then most of the time the result will be wrong.

If A and B are both int4, then you have to FORCE it to use INT8 arithmetic, or

the result will almost always be wrong.

Example: C=int8(a)*b

The problem is far worse with the ** operator, for example if A and B are just one byte integers,

and you say c=int8(a)**b then the result will almost always be wrong.

 

So, other than going to machine code, is there a way around this?

What about the C++ approach? Well, it doesn;t have as many choices for integer size -

 

 

0 Kudos
4 Replies
Steven_L_Intel1
Employee
1,546 Views

Sorry, no integer overflow checking is available. The processor doesn't have the ability to trap on integer overflows, so we would have to add checks after each operation. It's something we've wanted to do - CVF had it - but it just hasn't been possible yet. Maybe someday.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,546 Views

Assuming you are not using integer(8)

c=a*b
if(dbl(c) .ne. dbl(a)*dbl(b)) stop "integer overflow"

A better route would be to use the C interface on an assembler function you call with

c = MUL(a,b,istat) ! istat returns error

Where MUL has a generic interface that accepts differing integer types (and if desired real types). And dispatches to the appropriate function call using C interface to assembler function. In assembly, it is relatively easy to determine if the product of two integers overflow. (same with addition).

You could also use a variation on this to construct multi-precision

anINT8 = MUL(anINT4, anotherINT4) 

Steve, in addition to a runtime check the performs integer overflow tests on all operations, it might be useful to have a set of intrinsic functions that perform the tests while producing the results.

Jim Dempsey

0 Kudos
WSinc
New Contributor I
1,546 Views

Another approach I considered was using real(16) arithmetic.

Integer A,B,C

REAL(16) CC

CC=real(A,16)*real(b,16)

C=CC

The reason being you can get 33 places of accuracy, so thats about as good as integer(16)

which doesn't exist in our Fortran package. I tested it for the most extreme case, namely

when A and B are = 2**32-1 or -2**32 for integer(4) inputs.

The disadvantage there is it uses a lot more processing time.

However, if you are going to use it to CHECK the result,

you might as well use it to GIVE the result.

If A and B are integer(8) then the most extreme cases are - 2**64 and +2**64-1

This approach still fails with exponentiation, however, since as I pointed out before, you get huge numbers

from very small A and B. Maybe it works up to 16 byte integers though.

 

0 Kudos
JVanB
Valued Contributor II
1,546 Views

Looking at polyhedron's web pages, it seems that gfortran is the only one with integer(16). So I tried:

subroutine MULL(a,b,chi,clo) bind(C)
   use ISO_FORTRAN_ENV
   implicit none
   integer(INT64), value :: a, b
   integer(INT64), intent(out) :: chi,clo
   integer, parameter :: INT128 = selected_int_kind(30)
   integer(INT128), parameter :: mask = MASKR(64,INT128)
   integer(INT128) c

   c = IAND(mask,INT(a,INT128))*IAND(mask,INT(b,INT128))
   chi = IBITS(c,64,64)
   clo = c
end subroutine MULL

and gfortran -O2 -fomit-frame-pointer -S MULL.f90 knocked it out of the park!

 .file "MULL.f90"
 .section .text.unlikely,"x"
.LCOLDB0:
 .text
.LHOTB0:
 .p2align 4,,15
 .globl mull
 .def mull; .scl 2; .type 32; .endef
 .seh_proc mull
mull:
 .seh_endprologue
 movq %rcx, %rax
 mulq %rdx
 movq %rdx, (%r8)
 movq %rax, (%r9)
 ret
 .seh_endproc
 .section .text.unlikely,"x"
.LCOLDE0:
 .text
.LHOTE0:
 .ident "GCC: (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 4.9.2"

As I said in another thread, it would be really cool to know how to get ifort to spit out a mulq like that.

 

0 Kudos
Reply