]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/ieee754/ldbl-128ibm/e_powl.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / sysdeps / ieee754 / ldbl-128ibm / e_powl.c
index 52ce33abaae4f3775443ae1c35ca2139871005cb..df09c87662d7966f1ea2b848a5f6fea0883b42a9 100644 (file)
@@ -28,7 +28,7 @@
 
     You should have received a copy of the GNU Lesser General Public
     License along with this library; if not, see
-    <http://www.gnu.org/licenses/>.  */
+    <https://www.gnu.org/licenses/>.  */
 
 /* __ieee754_powl(x,y) return x**y
  *
@@ -66,6 +66,7 @@
 
 #include <math.h>
 #include <math_private.h>
+#include <math-underflow.h>
 
 static const long double bp[] = {
   1.0L,
@@ -88,8 +89,8 @@ static const long double zero = 0.0L,
   one = 1.0L,
   two = 2.0L,
   two113 = 1.0384593717069655257060992658440192E34L,
-  huge = 1.0e3000L,
-  tiny = 1.0e-3000L;
+  huge = 1.0e300L,
+  tiny = 1.0e-300L;
 
 /* 3/2 log x = 3 z + z^3 + z^3 (z^2 R(z^2))
    z = (x-1)/(x+1)
@@ -148,40 +149,35 @@ long double
 __ieee754_powl (long double x, long double y)
 {
   long double z, ax, z_h, z_l, p_h, p_l;
-  long double y1, t1, t2, r, s, t, u, v, w;
-  long double s2, s_h, s_l, t_h, t_l;
+  long double y1, t1, t2, r, s, sgn, t, u, v, w;
+  long double s2, s_h, s_l, t_h, t_l, ay;
   int32_t i, j, k, yisint, n;
-  u_int32_t ix, iy;
-  int32_t hx, hy;
-  ieee854_long_double_shape_type o, p, q;
+  uint32_t ix, iy;
+  int32_t hx, hy, hax;
+  double ohi, xhi, xlo, yhi, ylo;
+  uint32_t lx, ly, lj;
 
-  p.value = x;
-  hx = p.parts32.w0;
+  ldbl_unpack (x, &xhi, &xlo);
+  EXTRACT_WORDS (hx, lx, xhi);
   ix = hx & 0x7fffffff;
 
-  q.value = y;
-  hy = q.parts32.w0;
+  ldbl_unpack (y, &yhi, &ylo);
+  EXTRACT_WORDS (hy, ly, yhi);
   iy = hy & 0x7fffffff;
 
-
   /* y==zero: x**0 = 1 */
-  if ((iy | q.parts32.w1 | (q.parts32.w2 & 0x7fffffff) | q.parts32.w3) == 0)
+  if ((iy | ly) == 0 && !issignaling (x))
     return one;
 
   /* 1.0**y = 1; -1.0**+-Inf = 1 */
-  if (x == one)
+  if (x == one && !issignaling (y))
     return one;
-  if (x == -1.0L && iy == 0x7ff00000
-      && (q.parts32.w1 | (q.parts32.w2 & 0x7fffffff) | q.parts32.w3) == 0)
+  if (x == -1.0L && ((iy - 0x7ff00000) | ly) == 0)
     return one;
 
   /* +-NaN return x+y */
-  if ((ix > 0x7ff00000)
-      || ((ix == 0x7ff00000)
-         && ((p.parts32.w1 | (p.parts32.w2 & 0x7fffffff) | p.parts32.w3) != 0))
-      || (iy > 0x7ff00000)
-      || ((iy == 0x7ff00000)
-         && ((q.parts32.w1 | (q.parts32.w2 & 0x7fffffff) | q.parts32.w3) != 0)))
+  if ((ix >= 0x7ff00000 && ((ix - 0x7ff00000) | lx) != 0)
+      || (iy >= 0x7ff00000 && ((iy - 0x7ff00000) | ly) != 0))
     return x + y;
 
   /* determine if y is an odd int when x < 0
@@ -192,14 +188,17 @@ __ieee754_powl (long double x, long double y)
   yisint = 0;
   if (hx < 0)
     {
-      if ((q.parts32.w2 & 0x7fffffff) >= 0x43400000)   /* Low part >= 2^53 */
+      uint32_t low_ye;
+
+      GET_HIGH_WORD (low_ye, ylo);
+      if ((low_ye & 0x7fffffff) >= 0x43400000) /* Low part >= 2^53 */
        yisint = 2;             /* even integer y */
       else if (iy >= 0x3ff00000)       /* 1.0 */
        {
-         if (__floorl (y) == y)
+         if (floorl (y) == y)
            {
              z = 0.5 * y;
-             if (__floorl (z) == z)
+             if (floorl (z) == z)
                yisint = 2;
              else
                yisint = 1;
@@ -207,42 +206,43 @@ __ieee754_powl (long double x, long double y)
        }
     }
 
+  ax = fabsl (x);
+
   /* special value of y */
-  if ((q.parts32.w1 | (q.parts32.w2 & 0x7fffffff) | q.parts32.w3) == 0)
+  if (ly == 0)
     {
-      if (iy == 0x7ff00000 && q.parts32.w1 == 0)       /* y is +-inf */
+      if (iy == 0x7ff00000)    /* y is +-inf */
        {
-         if (((ix - 0x3ff00000) | p.parts32.w1
-              | (p.parts32.w2 & 0x7fffffff) | p.parts32.w3) == 0)
-           return y - y;       /* inf**+-1 is NaN */
-         else if (ix > 0x3ff00000 || fabsl (x) > 1.0L)
+         if (ax > one)
            /* (|x|>1)**+-inf = inf,0 */
            return (hy >= 0) ? y : zero;
          else
            /* (|x|<1)**-,+inf = inf,0 */
            return (hy < 0) ? -y : zero;
        }
-      if (iy == 0x3ff00000)
-       {                       /* y is  +-1 */
-         if (hy < 0)
-           return one / x;
-         else
-           return x;
-       }
-      if (hy == 0x40000000)
-       return x * x;           /* y is  2 */
-      if (hy == 0x3fe00000)
-       {                       /* y is  0.5 */
-         if (hx >= 0)          /* x >= +0 */
-           return __ieee754_sqrtl (x);
+      if (ylo == 0.0)
+       {
+         if (iy == 0x3ff00000)
+           {                   /* y is  +-1 */
+             if (hy < 0)
+               return one / x;
+             else
+               return x;
+           }
+         if (hy == 0x40000000)
+           return x * x;               /* y is  2 */
+         if (hy == 0x3fe00000)
+           {                   /* y is  0.5 */
+             if (hx >= 0)              /* x >= +0 */
+               return sqrtl (x);
+           }
        }
     }
 
-  ax = fabsl (x);
   /* special value of x */
-  if ((p.parts32.w1 | (p.parts32.w2 & 0x7fffffff) | p.parts32.w3) == 0)
+  if (lx == 0)
     {
-      if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000)
+      if (ix == 0x7ff00000 || ix == 0 || (ix == 0x3ff00000 && xlo == 0.0))
        {
          z = ax;               /*x is +-0,+-inf,+-1 */
          if (hy < 0)
@@ -261,9 +261,14 @@ __ieee754_powl (long double x, long double y)
     }
 
   /* (x<0)**(non-int) is NaN */
-  if (((((u_int32_t) hx >> 31) - 1) | yisint) == 0)
+  if (((((uint32_t) hx >> 31) - 1) | yisint) == 0)
     return (x - x) / (x - x);
 
+  /* sgn (sign of result -ve**odd) = -1 else = 1 */
+  sgn = one;
+  if (((((uint32_t) hx >> 31) - 1) | (yisint - 1)) == 0)
+    sgn = -one;                        /* (-ve)**(odd int) */
+
   /* |y| is huge.
      2^-16495 = 1/2 of smallest representable value.
      If (1 - 1/131072)^y underflows, y > 1.4986e9 */
@@ -273,25 +278,29 @@ __ieee754_powl (long double x, long double y)
       if (iy > 0x47d654b0)
        {
          if (ix <= 0x3fefffff)
-           return (hy < 0) ? huge * huge : tiny * tiny;
+           return (hy < 0) ? sgn * huge * huge : sgn * tiny * tiny;
          if (ix >= 0x3ff00000)
-           return (hy > 0) ? huge * huge : tiny * tiny;
+           return (hy > 0) ? sgn * huge * huge : sgn * tiny * tiny;
        }
       /* over/underflow if x is not close to one */
       if (ix < 0x3fefffff)
-       return (hy < 0) ? huge * huge : tiny * tiny;
+       return (hy < 0) ? sgn * huge * huge : sgn * tiny * tiny;
       if (ix > 0x3ff00000)
-       return (hy > 0) ? huge * huge : tiny * tiny;
+       return (hy > 0) ? sgn * huge * huge : sgn * tiny * tiny;
     }
 
+  ay = y > 0 ? y : -y;
+  if (ay < 0x1p-117)
+    y = y < 0 ? -0x1p-117 : 0x1p-117;
+
   n = 0;
   /* take care subnormal number */
   if (ix < 0x00100000)
     {
       ax *= two113;
       n -= 113;
-      o.value = ax;
-      ix = o.parts32.w0;
+      ohi = ldbl_high (ax);
+      GET_HIGH_WORD (ix, ohi);
     }
   n += ((ix) >> 20) - 0x3ff;
   j = ix & 0x000fffff;
@@ -308,26 +317,19 @@ __ieee754_powl (long double x, long double y)
       ix -= 0x00100000;
     }
 
-  o.value = ax;
-  o.value = __scalbnl (o.value, ((int) ((ix - o.parts32.w0) * 2)) >> 21);
-  ax = o.value;
+  ohi = ldbl_high (ax);
+  GET_HIGH_WORD (hax, ohi);
+  ax = __scalbnl (ax, ((int) ((ix - hax) * 2)) >> 21);
 
   /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
   u = ax - bp[k];              /* bp[0]=1.0, bp[1]=1.5 */
   v = one / (ax + bp[k]);
   s = u * v;
-  s_h = s;
+  s_h = ldbl_high (s);
 
-  o.value = s_h;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  s_h = o.value;
   /* t_h=ax+bp[k] High */
   t_h = ax + bp[k];
-  o.value = t_h;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  t_h = o.value;
+  t_h = ldbl_high (t_h);
   t_l = ax - (t_h - bp[k]);
   s_l = v * ((u - s_h * t_h) - s_h * t_l);
   /* compute log(ax) */
@@ -338,70 +340,50 @@ __ieee754_powl (long double x, long double y)
   r += s_l * (s_h + s);
   s2 = s_h * s_h;
   t_h = 3.0 + s2 + r;
-  o.value = t_h;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  t_h = o.value;
+  t_h = ldbl_high (t_h);
   t_l = r - ((t_h - 3.0) - s2);
   /* u+v = s*(1+...) */
   u = s_h * t_h;
   v = s_l * t_h + t_l * s;
   /* 2/(3log2)*(s+...) */
   p_h = u + v;
-  o.value = p_h;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  p_h = o.value;
+  p_h = ldbl_high (p_h);
   p_l = v - (p_h - u);
   z_h = cp_h * p_h;            /* cp_h+cp_l = 2/(3*log2) */
   z_l = cp_l * p_h + p_l * cp + dp_l[k];
   /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
   t = (long double) n;
   t1 = (((z_h + z_l) + dp_h[k]) + t);
-  o.value = t1;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  t1 = o.value;
+  t1 = ldbl_high (t1);
   t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
 
-  /* s (sign of result -ve**odd) = -1 else = 1 */
-  s = one;
-  if (((((u_int32_t) hx >> 31) - 1) | (yisint - 1)) == 0)
-    s = -one;                  /* (-ve)**(odd int) */
-
   /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
-  y1 = y;
-  o.value = y1;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  y1 = o.value;
+  y1 = ldbl_high (y);
   p_l = (y - y1) * t1 + y * t2;
   p_h = y1 * t1;
   z = p_l + p_h;
-  o.value = z;
-  j = o.parts32.w0;
+  ohi = ldbl_high (z);
+  EXTRACT_WORDS (j, lj, ohi);
   if (j >= 0x40d00000) /* z >= 16384 */
     {
       /* if z > 16384 */
-      if (((j - 0x40d00000) | o.parts32.w1
-       | (o.parts32.w2 & 0x7fffffff) | o.parts32.w3) != 0)
-       return s * huge * huge; /* overflow */
+      if (((j - 0x40d00000) | lj) != 0)
+       return sgn * huge * huge;       /* overflow */
       else
        {
          if (p_l + ovt > z - p_h)
-           return s * huge * huge;     /* overflow */
+           return sgn * huge * huge;   /* overflow */
        }
     }
   else if ((j & 0x7fffffff) >= 0x40d01b90)     /* z <= -16495 */
     {
       /* z < -16495 */
-      if (((j - 0xc0d01bc0) | o.parts32.w1
-        | (o.parts32.w2 & 0x7fffffff) | o.parts32.w3) != 0)
-       return s * tiny * tiny; /* underflow */
+      if (((j - 0xc0d01bc0) | lj) != 0)
+       return sgn * tiny * tiny;       /* underflow */
       else
        {
          if (p_l <= z - p_h)
-           return s * tiny * tiny;     /* underflow */
+           return sgn * tiny * tiny;   /* underflow */
        }
     }
   /* compute 2**(p_h+p_l) */
@@ -410,15 +392,12 @@ __ieee754_powl (long double x, long double y)
   n = 0;
   if (i > 0x3fe00000)
     {                          /* if |z| > 0.5, set n = [z+0.5] */
-      n = __floorl (z + 0.5L);
+      n = floorl (z + 0.5L);
       t = n;
       p_h -= t;
     }
   t = p_l + p_h;
-  o.value = t;
-  o.parts32.w3 = 0;
-  o.parts32.w2 &= 0xffff8000;
-  t = o.value;
+  t = ldbl_high (t);
   u = t * lg2_h;
   v = (p_l - (t - p_h)) * lg2 + t * lg2_l;
   z = u + v;
@@ -430,7 +409,8 @@ __ieee754_powl (long double x, long double y)
   t1 = z - t * u / v;
   r = (z * t1) / (t1 - two) - (w + z * w);
   z = one - (r - z);
-  z = __scalbnl (z, n);
-  return s * z;
+  z = __scalbnl (sgn * z, n);
+  math_check_force_underflow (z);
+  return z;
 }
 strong_alias (__ieee754_powl, __powl_finite)