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

Q about integer multiply

WSinc
Nouveau contributeur I
4 725 Visites

Suppose we have:

      integer(4) x,y

      integer (8) z

      z=x*y

In almost all cases, the result will be wrong, in fact, more than 99.9999 percent of the

time, since the compiler does not understand that the result can be more than 4 bytes.

This wrong result is not detected, since apparently the compiler does not check for an overflow.

At least, not on the INTEL compiler, although in my work at Aerospace and JPL IBM 7094

main frames, it did tell you about the overflow.

so to avoid this, I have to say:

       z=int(x,8)*y

Is there a simpler way around this? Maybe the compiler people should take a serious look at this.

You see the same problem with INTEGER(1) AND INTEGER(2) variables, BTW...........

 

As well as with the ADD operator. seems like an overflow check would be a simple answer,

though it does slow down things. So maybe as an option ?

0 Compliments
12 Réponses
Arjen_Markus
Contributeur émérite II
4 721 Visites

I think your mental model is slightly wrong: it is not a matter of the compiler not understanding that the result can be larger than expressable in 4 bytes, but the Fortran standard prescribes that the right-hand side is evaluated independently of the left-hand side.

Furthermore, if I understand these matters correctly, detecting overflows and other such unusual conditions is a task for the computer's processor, not for the compiler/runtime and most hardware checks only for floating-point exceptions. I think I read somewhere that this behaviour (silent overlfows) is even expected in a lot of software.

The simplest solution is: do not mix different types of integers. I would use the kind mechanism to define integers of the desired range, just as is commonly done for reals. 

0 Compliments
TimP
Contributeur émérite III
4 722 Visites

In fact, Fortran on the 7094 didn't support mixed data types, nor even any precursor of KIND.  Later f66 compilers support mixed data types only outside the standard, with vendor-specific treatments.

0 Compliments
WSinc
Nouveau contributeur I
4 722 Visites

The problem with having ALL INTEGERS OF THE SAME TYPE, is that you can use up a lot of unwanted storage that way.

Suppose, for example, you want to get the largest product from two arrays of integer(1):

integer (1)  x(1000000), y (1000000)

integer(2) xymax/0/,xy

do i=1,1000000

do j=1,1000000

xy=int(x(i),2)*y(j)

xymax=max(xymax,xy)

enddo

enddo

Print *,xymax=",xymax

It would be really stupid to make those integer arrays integer(2) and waste 2000000 bytes of storage,

don't you agree?

Of, course in this case, one should take the MAX of each array, then multiply that, but this is

just to illustrate the point.

If you know that no integer is > 127, then integer(1) is the largest you would make them.

Unfortunately, FORTEAN 95 does not give us a convenient way to multiply two INTEGER(8) quantities,

or even INTEGER(8) by a smaller size integer, with getting an overflow and detecting it. One can, however, simulate it by using

REAL(16), though, as follows:

real(16)  xy

integer(8) x,y

xy=real(x,16)*real(y,16) ! they dont both HAVE to be real

You still would have trouble storing the result, however.

Also REAL(16) cannot handle a 126 bit result, since some of the 16 bytes (12 bits ?) is used by the exponent.

The largest product you can have is (2**63-1)*(2**63-1) which would be 126 bits long.

0 Compliments
andrew_4619
Contributeur émérite III
4 722 Visites

so to avoid this, I have to say:

       z=int(x,8)*y

Is there a simpler way around this?

It isn't exactly a complicated solution is it? Or would an 'easier' solution be to redfnne how the Fortran language works?

 

0 Compliments
WSinc
Nouveau contributeur I
4 721 Visites

Well, the really bad part is you can get completely wrong answers without KNOWING it.

That can be really critical if you have a really serious application.

 

For example : Medical, space travel, missile launching, etc.

0 Compliments
WSinc
Nouveau contributeur I
4 721 Visites

arjenmarkus said "the right side is evaluated independently."

But it does NOT evaluate the RHS properly if the result is too big to fit.

Unless one forces it by using int(*,8), int (*,4), etc.

 

Storing it, well, that's a different matter.

0 Compliments
dboggs
Nouveau contributeur I
4 722 Visites

Bill,

Pardon my French but as someone who has apparently been working with Fortran (and FORTRAN) for quite a few years, you should know about the risk of overflow in situations exactly like this. It has been this way for about 60 years. The way to protect against it is as others have already indicated.

0 Compliments
JVanB
Précieux contributeur II
4 722 Visites

It does seem a great pity that Haswell has such nice primitives as MULX, ADCX, and ADOX for performing bignum arithmetic, but Intel's Fortran compiler does not give us access to them.

 

0 Compliments
WSinc
Nouveau contributeur I
4 722 Visites

I have been using Fortran myself for over 50 years, since the Fortran II days.

But Intel is the only company that ignores integer overflow situations, that I have ever seen.

Even if we take all these precautions, it can still bite you in the tush.

How do I get the Haswell product ?

0 Compliments
mecej4
Contributeur émérite III
4 721 Visites

billsincl wrote:

How do I get the Haswell product ?

Mainstream Haswells do not support ADCOX. Some (all? I'm not sure, need to search and read Intel processor manuals to find out) Haswell-E processors do. What this implies is that if you want ADCOX instructions on, say, a laptop, you need a Broadwell or a Skylake CPU.

Even if the CPU has some desired instructions/features in its repertoire, you need support in the programming language or through support libraries and, sometimes, in the OS and even the BIOS and motherboard.

You can find out what features are available in a specific CPU by running the following C program if you have the IPP library and the Intel C compiler installed.

#include <stdio.h>
#include <ippcore.h>
int main(){
  Ipp64u mask; IppStatus stat;

  stat=ippGetCpuFeatures(&mask,NULL);

  printf("stat(ADCOX) = %1d\n",mask & ippCPUID_ADCOX ? 1 : 0);
  printf("stat(AVX)   = %1d\n",mask & ippCPUID_AVX   ? 1 : 0);
  printf("stat(SSSE3) = %1d\n",mask & ippCPUID_SSSE3 ? 1 : 0);
}

If the first line prints a non-zero, the ADCOX feature is available but, if your software does not allow you to exploit the capability in a convenient manner, in effect it is not available.

All that said, I think that you are making much ado about little and have unreasonable expectations. Generations of programmers have survived life without hardware interrupt/trap on integer overflow. If n-byte integers were provided, invariably some users would be asking for 2.n-byte support (in this thread, n <= 4). On x86/x64 the INTO instruction is available for use with the flags register to catch overflow, but needs support in the compiler. Some Windows Fortran compilers do let you check for integer overflow (at the expense of slowing down your programs).

0 Compliments
JVanB
Précieux contributeur II
4 721 Visites

I guess you're right about not having ADOX/ADCX instructions. I wrote up something to check via CPUID:

; fasm mulx.asm
format MS64 coff

section '.code' code readable executable
public FTN_CPUID
FTN_CPUID:
xchg eax, edx
xchg eax, ecx
CPUID
mov [r8], eax
mov [r8+4], ecx
mov [r8+8], edx
mov [r8+12], ebx
ret
! ifort /nologo adox.f90 mulx.obj
program P
   use ISO_FORTRAN_ENV
   implicit none
   interface
      subroutine FTN_CPUID(eax,ecx,results) bind(C,name='FTN_CPUID')
         import
         implicit none
         integer(INT32), value :: eax
         integer(INT32), value :: ecx
         integer(INT32) results(4)
      end subroutine FTN_CPUID
   end interface
   integer(INT32) eax
   integer(INT32) ecx
   integer(INT32) results(4)

   eax = int(Z'01',INT32)
   ecx = int(Z'00',INT32)
   write(*,'(a)') 'Input:'
   write(*,'(a,z8.8)') 'eax = ', eax
   write(*,'(a,z8.8)') 'ecx = ', ecx
   call FTN_CPUID(eax,ecx,results)
   write(*,'(a)') 'Outut:'
   write(*,'(a,z8.8)') 'eax = ', results(1)
   write(*,'(a,z8.8)') 'ecx = ', results(2)
   write(*,'(a,z8.8)') 'edx = ', results(3)
   write(*,'(a,z8.8)') 'ebx = ', results(4)
   eax = int(Z'07',INT32)
   ecx = int(Z'00',INT32)
   write(*,'(a)') 'Input:'
   write(*,'(a,z8.8)') 'eax = ', eax
   write(*,'(a,z8.8)') 'ecx = ', ecx
   call FTN_CPUID(eax,ecx,results)
   write(*,'(a)') 'Outut:'
   write(*,'(a,z8.8)') 'eax = ', results(1)
   write(*,'(a,z8.8)') 'ecx = ', results(2)
   write(*,'(a,z8.8)') 'edx = ', results(3)
   write(*,'(a,z8.8)') 'ebx = ', results(4)
end program P
Input:
eax = 00000001
ecx = 00000000
Outut:
eax = 000306C3
ecx = 7FFAFBFF
edx = BFEBFBFF
ebx = 05100800
Input:
eax = 00000007
ecx = 00000000
Outut:
eax = 00000000
ecx = 00000000
edx = 00000000
ebx = 000027AB

The first CPUID shows

Processor Type = B'00' -- Original OEM Processor

Family ID = Z'06' = Display Family

Model ID = Z'0C'

Extended Model ID = Z'03' => Display Model = Z'3C' => Haswell (not E)

Stepping ID = Z'03'

The second CPUID shows

BMI2 = .TRUE. => MULX available

ADX = .FALSE. => ADOX/ADCX not available :(

 

0 Compliments
jimdempseyatthecove
Contributeur émérite III
4 721 Visites

integer(8) :: x, y, z

z = x * y
if(z / y .ne. x) then
  ! overflow

Jim Dempsey

0 Compliments
Répondre