- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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 -
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page