https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96807

            Bug ID: 96807
           Summary: Division by zero produces zero with gcc -O2
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: fazedo at gmail dot com
  Target Milestone: ---

Hello,

The following code produces 1/0 = 0 with gcc -O2: 


--------
#include <stdio.h>
#include <stdlib.h>

int main(int argn, char** argc){
  unsigned base = argn>1 ? atoi(argc[1]) : 0;
  if (base!=1) printf("%d\n", 1/base); // produces 0 for base=0 with -O2
  return 0; 
}
--------

The same behavior occurs with clang but not with icc.  If 1/base is not guarded
by if or if base is a signed integer, it produces a floating point exception
even with -O2. 

As a result, Fortran's intrinsic power operator (**) applied to integers is
producing wrong results when the base is zero and the exponent is negative.
Instead of giving division by zero or infinity, it gives zero.

The code given below shows that base**(-1) yields 0 when base=0. 

It is my understanding that gfortran calls functions pow_iX_iY from
libgfortran/generated. These functions are correctly coded but they produce
0**n=0 for n<0 due to optimizations when libgfortran is compiled. 

--------
program power
  implicit none
  integer (kind = 4) :: base = 0

  print *, base**(-1)           ! produces 0
  print *, real(base, 4)**(-1)  ! produces infinity
end program
--------


By the way, is there any advantage to using the pow_XX_YY.c functions on
libgfortran/generated instead of __powiXX2 (and its integer version) defined
for __builtin_powi on libgcc2.c?

It seems to me that libgcc2's version reads much better and should be a little
faster because it saves the first multiplication (by pow=1).

The only difference in behaviour I see is that when the exponent is negative
and the base if a floating point type, libgcc2 calculates 1/(x**(-n)) while
libgfortran calculates (1/x)**(-n). The first version being more accurate.

I am using gcc 9.3.0 on x86-64.

Best regards,
Fabio Azevedo

Reply via email to