Blame math/divtc3.c

Packit 6c4009
/* Copyright (C) 2005-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Richard Henderson <rth@redhat.com>, 2005.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <complex.h>
Packit 6c4009
Packit 6c4009
attribute_hidden
Packit 6c4009
long double _Complex
Packit 6c4009
__divtc3 (long double a, long double b, long double c, long double d)
Packit 6c4009
{
Packit 6c4009
  long double denom, ratio, x, y;
Packit 6c4009
Packit 6c4009
  /* ??? We can get better behavior from logarithmic scaling instead of
Packit 6c4009
     the division.  But that would mean starting to link libgcc against
Packit 6c4009
     libm.  We could implement something akin to ldexp/frexp as gcc builtins
Packit 6c4009
     fairly easily...  */
Packit 6c4009
  if (fabsl (c) < fabsl (d))
Packit 6c4009
    {
Packit 6c4009
      ratio = c / d;
Packit 6c4009
      denom = (c * ratio) + d;
Packit 6c4009
      x = ((a * ratio) + b) / denom;
Packit 6c4009
      y = ((b * ratio) - a) / denom;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      ratio = d / c;
Packit 6c4009
      denom = (d * ratio) + c;
Packit 6c4009
      x = ((b * ratio) + a) / denom;
Packit 6c4009
      y = (b - (a * ratio)) / denom;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Recover infinities and zeros that computed as NaN+iNaN; the only cases
Packit 6c4009
     are nonzero/zero, infinite/finite, and finite/infinite.  */
Packit 6c4009
  if (isnan (x) && isnan (y))
Packit 6c4009
    {
Packit 6c4009
      if (denom == 0.0 && (!isnan (a) || !isnan (b)))
Packit 6c4009
	{
Packit 6c4009
	  x = __copysignl (INFINITY, c) * a;
Packit 6c4009
	  y = __copysignl (INFINITY, c) * b;
Packit 6c4009
	}
Packit 6c4009
      else if ((isinf (a) || isinf (b))
Packit 6c4009
	       && isfinite (c) && isfinite (d))
Packit 6c4009
	{
Packit 6c4009
	  a = __copysignl (isinf (a) ? 1 : 0, a);
Packit 6c4009
	  b = __copysignl (isinf (b) ? 1 : 0, b);
Packit 6c4009
	  x = INFINITY * (a * c + b * d);
Packit 6c4009
	  y = INFINITY * (b * c - a * d);
Packit 6c4009
	}
Packit 6c4009
      else if ((isinf (c) || isinf (d))
Packit 6c4009
	       && isfinite (a) && isfinite (b))
Packit 6c4009
	{
Packit 6c4009
	  c = __copysignl (isinf (c) ? 1 : 0, c);
Packit 6c4009
	  d = __copysignl (isinf (d) ? 1 : 0, d);
Packit 6c4009
	  x = 0.0 * (a * c + b * d);
Packit 6c4009
	  y = 0.0 * (b * c - a * d);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return x + I * y;
Packit 6c4009
}