/* { dg-options "-O0 -std=gnu99" } */

int
main (void)
{
  _Complex double d;
  __real__ d = 1.0;
  __imag__ d = 1.0;
  d = d / 0.0;
  if (!__builtin_isinf (__real__ d) || !__builtin_isinf (__imag__ d))
    __builtin_abort ();
  return 0;
}

fails when compiled with -O0 -std=c99 but succeeds when compiled with -O2
-std=c99.  ISO C99 says it should be (inf, inf) always in G.5.1 (4):
"if the first operand is a nonzero finite number or an infinity and the second
operand is a zero, then the result of the / operator is an infinity."

The problem is that libgcc _divdc3 doesn't do logarithmic scaling:
  /* ??? We can get better behavior from logarithmic scaling instead of
     the division.  But that would mean starting to link libgcc against
     libm.  We could implement something akin to ldexp/frexp as gcc builtins
     fairly easily...  */
  if (FABS (c) < FABS (d))
    {
      ratio = c / d;
      denom = (c * ratio) + d;
      x = ((a * ratio) + b) / denom;
      y = ((b * ratio) - a) / denom;
    }
  else
    {
      ratio = d / c;
      denom = (d * ratio) + c;
      x = ((b * ratio) + a) / denom;
      y = (b - (a * ratio)) / denom;
    }

so when c == d == 0.0, denom is not 0.0 as later code is testing, but NaN.
To fix this, I think we either need to switch to logarithmic scaling,
or we need to special case FABS (c) == FABS (d) case, or the denom == 0.0
change ought should change (would c == 0.0 && d == 0.0 be enough?).


-- 
           Summary: Complex divide bug
           Product: gcc
           Version: 4.1.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: jakub at gcc dot gnu dot org


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30360

Reply via email to