getaddrinfo: add EAI_NODATA error code to distinguish NODATA vs NxDomain
[musl] / src / math / sqrt.c
index 2ebd022..5ba2655 100644 (file)
-/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* sqrt(x)
- * Return correctly rounded sqrt.
- *           ------------------------------------------
- *           |  Use the hardware sqrt if you have one |
- *           ------------------------------------------
- * Method:
- *   Bit by bit method using integer arithmetic. (Slow, but portable)
- *   1. Normalization
- *      Scale x to y in [1,4) with even powers of 2:
- *      find an integer k such that  1 <= (y=x*2^(2k)) < 4, then
- *              sqrt(x) = 2^k * sqrt(y)
- *   2. Bit by bit computation
- *      Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
- *           i                                                   0
- *                                     i+1         2
- *          s  = 2*q , and      y  =  2   * ( y - q  ).         (1)
- *           i      i            i                 i
- *
- *      To compute q    from q , one checks whether
- *                  i+1       i
- *
- *                            -(i+1) 2
- *                      (q + 2      ) <= y.                     (2)
- *                        i
- *                                                            -(i+1)
- *      If (2) is false, then q   = q ; otherwise q   = q  + 2      .
- *                             i+1   i             i+1   i
- *
- *      With some algebric manipulation, it is not difficult to see
- *      that (2) is equivalent to
- *                             -(i+1)
- *                      s  +  2       <= y                      (3)
- *                       i                i
- *
- *      The advantage of (3) is that s  and y  can be computed by
- *                                    i      i
- *      the following recurrence formula:
- *          if (3) is false
- *
- *          s     =  s  ,       y    = y   ;                    (4)
- *           i+1      i          i+1    i
- *
- *          otherwise,
- *                         -i                     -(i+1)
- *          s     =  s  + 2  ,  y    = y  -  s  - 2             (5)
- *           i+1      i          i+1    i     i
- *
- *      One may easily use induction to prove (4) and (5).
- *      Note. Since the left hand side of (3) contain only i+2 bits,
- *            it does not necessary to do a full (53-bit) comparison
- *            in (3).
- *   3. Final rounding
- *      After generating the 53 bits result, we compute one more bit.
- *      Together with the remainder, we can decide whether the
- *      result is exact, bigger than 1/2ulp, or less than 1/2ulp
- *      (it will never equal to 1/2ulp).
- *      The rounding mode can be detected by checking whether
- *      huge + tiny is equal to huge, and whether huge - tiny is
- *      equal to huge for some floating point number "huge" and "tiny".
- *
- * Special cases:
- *      sqrt(+-0) = +-0         ... exact
- *      sqrt(inf) = inf
- *      sqrt(-ve) = NaN         ... with invalid signal
- *      sqrt(NaN) = NaN         ... with invalid signal for signaling NaN
- */
-
+#include <stdint.h>
+#include <math.h>
 #include "libm.h"
+#include "sqrt_data.h"
 
-static const double one = 1.0, tiny = 1.0e-300;
+#define FENV_SUPPORT 1
 
-double sqrt(double x)
+/* returns a*b*2^-32 - e, with error 0 <= e < 1.  */
+static inline uint32_t mul32(uint32_t a, uint32_t b)
 {
-       double z;
-       int32_t sign = (int)0x80000000;
-       int32_t ix0,s0,q,m,t,i;
-       uint32_t r,t1,s1,ix1,q1;
+       return (uint64_t)a*b >> 32;
+}
 
-       EXTRACT_WORDS(ix0, ix1, x);
+/* returns a*b*2^-64 - e, with error 0 <= e < 3.  */
+static inline uint64_t mul64(uint64_t a, uint64_t b)
+{
+       uint64_t ahi = a>>32;
+       uint64_t alo = a&0xffffffff;
+       uint64_t bhi = b>>32;
+       uint64_t blo = b&0xffffffff;
+       return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32);
+}
 
-       /* take care of Inf and NaN */
-       if ((ix0&0x7ff00000) == 0x7ff00000) {
-               return x*x + x;  /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
-       }
-       /* take care of zero */
-       if (ix0 <= 0) {
-               if (((ix0&~sign)|ix1) == 0)
-                       return x;  /* sqrt(+-0) = +-0 */
-               if (ix0 < 0)
-                       return (x-x)/(x-x);  /* sqrt(-ve) = sNaN */
-       }
-       /* normalize x */
-       m = ix0>>20;
-       if (m == 0) {  /* subnormal x */
-               while (ix0 == 0) {
-                       m -= 21;
-                       ix0 |= (ix1>>11);
-                       ix1 <<= 21;
-               }
-               for (i=0; (ix0&0x00100000) == 0; i++)
-                       ix0<<=1;
-               m -= i - 1;
-               ix0 |= ix1>>(32-i);
-               ix1 <<= i;
-       }
-       m -= 1023;    /* unbias exponent */
-       ix0 = (ix0&0x000fffff)|0x00100000;
-       if (m & 1) {  /* odd m, double x to make it even */
-               ix0 += ix0 + ((ix1&sign)>>31);
-               ix1 += ix1;
-       }
-       m >>= 1;      /* m = [m/2] */
-
-       /* generate sqrt(x) bit by bit */
-       ix0 += ix0 + ((ix1&sign)>>31);
-       ix1 += ix1;
-       q = q1 = s0 = s1 = 0;  /* [q,q1] = sqrt(x) */
-       r = 0x00200000;        /* r = moving bit from right to left */
-
-       while (r != 0) {
-               t = s0 + r;
-               if (t <= ix0) {
-                       s0   = t + r;
-                       ix0 -= t;
-                       q   += r;
-               }
-               ix0 += ix0 + ((ix1&sign)>>31);
-               ix1 += ix1;
-               r >>= 1;
-       }
+double sqrt(double x)
+{
+       uint64_t ix, top, m;
 
-       r = sign;
-       while (r != 0) {
-               t1 = s1 + r;
-               t  = s0;
-               if (t < ix0 || (t == ix0 && t1 <= ix1)) {
-                       s1 = t1 + r;
-                       if ((t1&sign) == sign && (s1&sign) == 0)
-                               s0++;
-                       ix0 -= t;
-                       if (ix1 < t1)
-                               ix0--;
-                       ix1 -= t1;
-                       q1 += r;
-               }
-               ix0 += ix0 + ((ix1&sign)>>31);
-               ix1 += ix1;
-               r >>= 1;
+       /* special case handling.  */
+       ix = asuint64(x);
+       top = ix >> 52;
+       if (predict_false(top - 0x001 >= 0x7ff - 0x001)) {
+               /* x < 0x1p-1022 or inf or nan.  */
+               if (ix * 2 == 0)
+                       return x;
+               if (ix == 0x7ff0000000000000)
+                       return x;
+               if (ix > 0x7ff0000000000000)
+                       return __math_invalid(x);
+               /* x is subnormal, normalize it.  */
+               ix = asuint64(x * 0x1p52);
+               top = ix >> 52;
+               top -= 52;
        }
 
-       /* use floating add to find out rounding direction */
-       if ((ix0|ix1) != 0) {
-               z = one - tiny; /* raise inexact flag */
-               if (z >= one) {
-                       z = one + tiny;
-                       if (q1 == (uint32_t)0xffffffff) {
-                               q1 = 0;
-                               q++;
-                       } else if (z > one) {
-                               if (q1 == (uint32_t)0xfffffffe)
-                                       q++;
-                               q1 += 2;
-                       } else
-                               q1 += q1 & 1;
-               }
+       /* argument reduction:
+          x = 4^e m; with integer e, and m in [1, 4)
+          m: fixed point representation [2.62]
+          2^e is the exponent part of the result.  */
+       int even = top & 1;
+       m = (ix << 11) | 0x8000000000000000;
+       if (even) m >>= 1;
+       top = (top + 0x3ff) >> 1;
+
+       /* approximate r ~ 1/sqrt(m) and s ~ sqrt(m) when m in [1,4)
+
+          initial estimate:
+          7bit table lookup (1bit exponent and 6bit significand).
+
+          iterative approximation:
+          using 2 goldschmidt iterations with 32bit int arithmetics
+          and a final iteration with 64bit int arithmetics.
+
+          details:
+
+          the relative error (e = r0 sqrt(m)-1) of a linear estimate
+          (r0 = a m + b) is |e| < 0.085955 ~ 0x1.6p-4 at best,
+          a table lookup is faster and needs one less iteration
+          6 bit lookup table (128b) gives |e| < 0x1.f9p-8
+          7 bit lookup table (256b) gives |e| < 0x1.fdp-9
+          for single and double prec 6bit is enough but for quad
+          prec 7bit is needed (or modified iterations). to avoid
+          one more iteration >=13bit table would be needed (16k).
+
+          a newton-raphson iteration for r is
+            w = r*r
+            u = 3 - m*w
+            r = r*u/2
+          can use a goldschmidt iteration for s at the end or
+            s = m*r
+
+          first goldschmidt iteration is
+            s = m*r
+            u = 3 - s*r
+            r = r*u/2
+            s = s*u/2
+          next goldschmidt iteration is
+            u = 3 - s*r
+            r = r*u/2
+            s = s*u/2
+          and at the end r is not computed only s.
+
+          they use the same amount of operations and converge at the
+          same quadratic rate, i.e. if
+            r1 sqrt(m) - 1 = e, then
+            r2 sqrt(m) - 1 = -3/2 e^2 - 1/2 e^3
+          the advantage of goldschmidt is that the mul for s and r
+          are independent (computed in parallel), however it is not
+          "self synchronizing": it only uses the input m in the
+          first iteration so rounding errors accumulate. at the end
+          or when switching to larger precision arithmetics rounding
+          errors dominate so the first iteration should be used.
+
+          the fixed point representations are
+            m: 2.30 r: 0.32, s: 2.30, d: 2.30, u: 2.30, three: 2.30
+          and after switching to 64 bit
+            m: 2.62 r: 0.64, s: 2.62, d: 2.62, u: 2.62, three: 2.62  */
+
+       static const uint64_t three = 0xc0000000;
+       uint64_t r, s, d, u, i;
+
+       i = (ix >> 46) % 128;
+       r = (uint32_t)__rsqrt_tab[i] << 16;
+       /* |r sqrt(m) - 1| < 0x1.fdp-9 */
+       s = mul32(m>>32, r);
+       /* |s/sqrt(m) - 1| < 0x1.fdp-9 */
+       d = mul32(s, r);
+       u = three - d;
+       r = mul32(r, u) << 1;
+       /* |r sqrt(m) - 1| < 0x1.7bp-16 */
+       s = mul32(s, u) << 1;
+       /* |s/sqrt(m) - 1| < 0x1.7bp-16 */
+       d = mul32(s, r);
+       u = three - d;
+       r = mul32(r, u) << 1;
+       /* |r sqrt(m) - 1| < 0x1.3704p-29 (measured worst-case) */
+       r = r << 32;
+       s = mul64(m, r);
+       d = mul64(s, r);
+       u = (three<<32) - d;
+       s = mul64(s, u);  /* repr: 3.61 */
+       /* -0x1p-57 < s - sqrt(m) < 0x1.8001p-61 */
+       s = (s - 2) >> 9; /* repr: 12.52 */
+       /* -0x1.09p-52 < s - sqrt(m) < -0x1.fffcp-63 */
+
+       /* s < sqrt(m) < s + 0x1.09p-52,
+          compute nearest rounded result:
+          the nearest result to 52 bits is either s or s+0x1p-52,
+          we can decide by comparing (2^52 s + 0.5)^2 to 2^104 m.  */
+       uint64_t d0, d1, d2;
+       double y, t;
+       d0 = (m << 42) - s*s;
+       d1 = s - d0;
+       d2 = d1 + s + 1;
+       s += d1 >> 63;
+       s &= 0x000fffffffffffff;
+       s |= top << 52;
+       y = asdouble(s);
+       if (FENV_SUPPORT) {
+               /* handle rounding modes and inexact exception:
+                  only (s+1)^2 == 2^42 m case is exact otherwise
+                  add a tiny value to cause the fenv effects.  */
+               uint64_t tiny = predict_false(d2==0) ? 0 : 0x0010000000000000;
+               tiny |= (d1^d2) & 0x8000000000000000;
+               t = asdouble(tiny);
+               y = eval_as_double(y + t);
        }
-       ix0 = (q>>1) + 0x3fe00000;
-       ix1 = q1>>1;
-       if (q&1)
-               ix1 |= sign;
-       ix0 += m << 20;
-       INSERT_WORDS(z, ix0, ix1);
-       return z;
+       return y;
 }