- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello -
as far as I know, in the current version of Fortran, we dont have a way to AUTOMATICALLY detect an integer overflow.
Of course, one can try to mitigate that by making integers 8 bytes long.
when I have short integers, I have to test to see (for example) if the sum of two positive integers is still positive.
But I don't think the CPU can detect a situation where the answer is wrong.
I was wondering if anything is being done to improve this situation.
In the olden days, we always got a trap if the result was too big to fit into the result.
On an IBM 7094, if you added two one byte integers whose result is >127, you would get an overflow trap.
Or if you multiplied 17*17, you would get a TRAP as well.
Of course, you might WANT the result to be possibly bigger:
integer(1) X/17/,y/17/
integer(2) XY
XY=X*Y
The compiler will NOT give you the right answer here, of course, since it will do an integer(1) multiply.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, there isn't currently a way to trap integer overflow, and I'm afraid there are no plans to create one. The processor doesn't flag integer overflows the way it does floating-point overflows.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was pretty sure the CPU cant do that, but do we have a way to tell the compiler to check the results?
That would be better than the PROGRAMMER having to put a bunch of numerical tests, cluttering up the code.
For example, we now have to say something like:
integer(1) a/17/, b/17/, C
C=a*b
if(c<0)print *,"Integer multiply is wrong ! !"
Don't you think that is kinda STUPID ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
billsincl wrote:
.. Don't you think that is kinda STUPID ? ..
@Bill,
You have been bringing this issue up for a long time now and you should now accept that the best option for you will be to do the handling of such situations by yourself. If you really wish to do run-time handling, I strongly suggest you look into using assert type of functionality, especially when you are debugging your code. Shown below is an example, can you please, please take a close look and see how you can use something like this?
Example of a custom assertion in Fortran:
module assert_m use, intrinsic :: iso_fortran_env, only : output_unit, I1 => int8, I2 => int16, I4 => int32, I8 => int64 implicit none private public :: assert contains subroutine assert( assertion, description, val, oun ) !.. Argument list logical, intent(in) :: assertion character(len=*), intent(in) :: description class(*), intent(in) :: val integer, intent(in), optional :: oun ! Output format character(len=*), parameter :: fmt_gen = "(*(g0))" ! Local variables integer, parameter :: MAX_LENGTH = 2048 ! suitable string size character(len=MAX_LENGTH) :: sval integer :: lun ! Output unit if ( present(oun) ) then lun = oun else lun = output_unit end if ! Process value select type ( val ) type is ( real ) blkr: block real :: rval rval = val write( sval, fmt=fmt_gen ) rval end block blkr type is ( integer(I1) ) blki1: block integer(I1) :: ival ival = val write( sval, fmt=fmt_gen ) ival end block blki1 type is ( integer(I2) ) blki2: block integer(I2) :: ival ival = val write( sval, fmt=fmt_gen ) ival end block blki2 type is ( integer(I4) ) blki4: block integer(I4) :: ival ival = val write( sval, fmt=fmt_gen ) ival end block blki4 type is ( integer(I8) ) blki8: block integer(I8) :: ival ival = val write( sval, fmt=fmt_gen ) ival end block blki8 type is ( character(len=*) ) sval = val class default sval = "val is of unknown type" end select ! Error stop if assertion is true if ( assertion ) then write( lun, fmt=fmt_gen ) "Assertion: " // trim(description) // ", value = " // trim(sval) error stop 1 end if return end subroutine assert end module assert_m
Modification of your program to make use the custom assertion: note it requires /DCODE_ASSERT compiler option:
program p use, intrinsic :: iso_fortran_env, only : I1 => int8, DP => real64 !dec$ if defined (CODE_ASSERT) use assert_m, only : assert !dec$ endif implicit none integer(I1) :: a, b, c a = 12 b = 12 c = a*b !dec$ if defined (CODE_ASSERT) blka1: block logical :: assertion real(DP) :: c_dp c_dp = real(a,dp)*real(b,dp) assertion = abs(c_dp-real(c,dp)) > epsilon(1.0_dp) call assert( assertion, "Integer overflow while computing c at line 14 in p.f90", c ) end block blka1 !dec$ endif print *, "c = ", c stop end program p
Upon execution using Intel Fortran, the above program gives:
Assertion: Integer overflow while computing c at line 14 in p.f90, value = -112 1
Now change the value of a to 10 and b to 11 and recompile and rerun the program and you should get:
c = 110 Press any key to continue . . .
And can this be the last time you bring this up? That you will use some option like the one above or look to other ways to refactor your code so the integer overflows do NOT occur in the first place. Thanks,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FWIW, it is possible to detect integer overflows on x86 - CVF did it. Unlike with floating overflow, it requires generating explicit code to check the processor flags after an integer instruction. However, the Intel code generator team has not considered it important enough to support, despite many customer requests. The code to do this is, by necessity, slower than without checking, though my view was that this was a perfectly appropriate debugging aid that users could enable or disable as they wished.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
billsincl wrote:
.. if(c<0)print *,"Integer multiply is wrong ! !" ..
@Bill,
Oh, I forgot to mention earlier: a check for negative result is NOT sufficient because the integer result can be based on (multiple) "wrap around" the range of the integer kind being used and the erroneous answer may be either positive or negative. So you need better checks; you can use some bitwise arithmetic to 'assert' the result more cleanly, but in my example I used floating-point to simply illustrate the custom handling option.
If you're concerned about 'code clutter', well your only recourse may be a code design review of your needs so that the issue can be avoided in the first place. That is unless someone else steps forward and gives you better ideas. But I see you have oft been asking about this and here you are again, so that should tell you something. Note though, with what I show with compiler directives, it is only 'clutter' in the source file; your 'production' code (e.g., Release versions of programs ) can be buiilt without such instructions by excluding the /D definition and thereby you can avoid any adverse impact with optimizations.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FortranFan wrote:
If you're concerned about 'code clutter', well your only recourse may be a code design review of your needs so that the issue can be avoided in the first place. That is unless someone else steps forward and gives you better ideas. But I see you have oft been asking about this and here you are again, so that should tell you something. Note though, with what I show with compiler directives, it is only 'clutter' in the source file; your 'production' code (e.g., Release versions of programs ) can be buiilt without such instructions by excluding the /D definition and thereby you can avoid any adverse impact with optimizations.
With the possible exception of a genuine integer overflow during production runs :).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Arjen Markus wrote:
Quote:
FortranFan wrote:
If you're concerned about 'code clutter', well your only recourse may be a code design review of your needs so that the issue can be avoided in the first place. That is unless someone else steps forward and gives you better ideas. But I see you have oft been asking about this and here you are again, so that should tell you something. Note though, with what I show with compiler directives, it is only 'clutter' in the source file; your 'production' code (e.g., Release versions of programs ) can be buiilt without such instructions by excluding the /D definition and thereby you can avoid any adverse impact with optimizations.
With the possible exception of a genuine integer overflow during production runs :).
Indeed! The expectation is that such situations have all been resolved during debugging and that with production, some form of 'assertion' exists at key points during the computations that then lead to appropriate treatment of the problem!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Using C interoperability, you can call the C function __readeflags() to read the eflags, then test the O flag (bit 11). You can also write a C function, that returns a Fortran LOGICAL as a result of the assembly instruction SETO (eax/rax receives 1 if O flag set, 0 if not). Give the function a name not likely to be of use elsewhere (e.g. C_EFLAGS_O). You can also add similar functions for C (carry), B (borrow), ...
then use as
c = a*b
if(C_EFLAGS_O()) STOP "Integer Overflow"
The above is not going to be vector friendly. For vector instructions you can use conditional movs, though some work will have to be done with the intrinsic calls.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
jimdempseyatthecove wrote:
Using C interoperability, you can call the C function __readeflags() to read the eflags, then test the O flag (bit 11). ..
Jim,
Do you have a working example with either Fortran or even just C? I did not think the eflags bit set with the integer arithmetic in Intel Fortran, especially with the wraparound.
Thanks,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On X86/X64 processors (and many others) the flags register sees a lot of action. Almost every instruction may change one or more flag bits.
The problem with using a high level language function call to query the flags is that the sequence of machine instructions that are executed to do just that may themselves change the flags register before it is read into a memory location - a la Heisenberg.
Furthermore, such calls will probably slow down the program considerably. I have seen programs slowed down by two orders of magnitude with Lahey/Fujitsu LF95 when their -Haesux error-checking options were used.
If there is a Fortran program that is suspected to have problems with integer overflow, it is best to use a compiler that can generate, upon request, INTO instructions after integer arithmetic instructions. A matching interrupt handler can then generate a traceback report.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The following is a solution with two projects: a C static library, and a Fortran program
// Chelper.c #include "stdafx.h" #include <intrin.h> int getEflags() { return __readeflags(); }
and
! eflagsTest.f90 program eflagsTest implicit none integer :: a,b,c integer(4) :: eflags integer, parameter :: eflags_O = Z"800" INTERFACE FUNCTION getEflags( ) bind( c, NAME='getEflags') import integer(4) :: getEflags ! INT END FUNCTION END INTERFACE a = Z'70000000' b = a c = a + 1 if(iand(getEflags(),eflags_O) /= 0) print *,"overflow" c = a + b if(iand(getEflags(),eflags_O) /= 0) print *,"overflow" end program eflagsTest
You can expand upon this. (e.g. add a logical function isOverflow) but be careful not to introduce statements that will alter the (e)flags.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Look, another use for an undocumented feature! No C required:
! eflagsTest.f90 program eflagsTest implicit none integer, volatile :: a,b,c integer(4) :: eflags integer, parameter :: eflags_O = Z"800" INTERFACE FUNCTION getEflags( ) bind( c, NAME='__readeflags') !DEC$ ATTRIBUTES KNOWN_INTRINSIC :: getEflags import integer(4) :: getEflags ! INT END FUNCTION END INTERFACE a = Z'70000000' b = a c = a + 1 if(iand(getEflags(),eflags_O) /= 0) print *,"overflow" c = a + b if(iand(getEflags(),eflags_O) /= 0) print *,"overflow" end program eflagsTest
I had to add the VOLATILE as otherwise the whole program was optimized away.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
Ahh... will (probably not) Intel document these attributes?
BTW, why is import required for an intrinsic function (i.e. non-library function)?
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
KNOWN_INTRINSIC is an internal-use hack that was created to support a couple of OpenMP functions that the code generator "knows". This isn't related to Fortran intrinsics. In Fortran, you can use this to get at some (but not all) instruction intrinsics that Intel C++ supports - the arguments and function results have to be simple types - if the intrinsic is described as taking special register type arguments, it won't work. I have successfully used this for CPUID.
I doubt it will ever be documented, but it can be handy if you figure out how to use it. Unsupported, of course!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Good afternoon,
Thanks a lot Steve for that hint. Is the name of the function in the BIND clause identical in 64 bit Windows or the leading underscores have to be removed?
I was quite active several years ago in the Fortran community, and with a new artificial intelligence project, I am coming back again.
Congratulations Steve for all your work for Intel and about Fortran in particular.
Regards,
Jean
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The name in the BIND(C) is the name of the C++ intrinsic - has no relation with procedure name decoration. It isn't a procedure at all, this was just a simple way to get the compiler "back end" to recognize a particular usage,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks a lot for the clarification!
Regards,
Jean
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page