Piotr Caban : msvcrt: Import sqrt from musl.

Alexandre Julliard julliard at winehq.org
Tue Aug 4 15:26:35 CDT 2020


Module: wine
Branch: master
Commit: a6ae2b5c1101d37f06c4118a6e4045dca7dfdc65
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=a6ae2b5c1101d37f06c4118a6e4045dca7dfdc65

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Tue Aug  4 15:17:33 2020 +0200

msvcrt: Import sqrt from musl.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msvcrt/math.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 108 insertions(+), 3 deletions(-)

diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index bbb5a9194e..59b6a98487 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -645,12 +645,117 @@ double CDECL MSVCRT_sinh( double x )
 
 /*********************************************************************
  *		MSVCRT_sqrt (MSVCRT.@)
+ *
+ * Copied from musl: src/math/sqrt.c
  */
 double CDECL MSVCRT_sqrt( double x )
 {
-  double ret = sqrt(x);
-  if (x < 0.0) return math_error(_DOMAIN, "sqrt", x, 0, ret);
-  return ret;
+    static const double tiny = 1.0e-300;
+
+    double z;
+    int sign = 0x80000000;
+    int ix0,s0,q,m,t,i;
+    unsigned int r,t1,s1,ix1,q1;
+    ULONGLONG ix;
+
+    ix = *(ULONGLONG*)&x;
+    ix0 = ix >> 32;
+    ix1 = ix;
+
+    /* take care of Inf and NaN */
+    if (isnan(x) || (isinf(x) && x > 0))
+        return x;
+
+    /* take care of zero */
+    if (ix0 <= 0) {
+        if (((ix0 & ~sign) | ix1) == 0)
+            return x;  /* sqrt(+-0) = +-0 */
+        if (ix0 < 0)
+            return math_error(_DOMAIN, "sqrt", x, 0, (x - x) / (x - x));
+    }
+    /* 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;
+    }
+
+    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;
+    }
+
+    /* use floating add to find out rounding direction */
+    if ((ix0 | ix1) != 0) {
+        z = 1.0 - tiny; /* raise inexact flag */
+        if (z >= 1.0) {
+            z = 1.0 + tiny;
+            if (q1 == (unsigned int)0xffffffff) {
+                q1 = 0;
+                q++;
+            } else if (z > 1.0) {
+                if (q1 == (unsigned int)0xfffffffe)
+                    q++;
+                q1 += 2;
+            } else
+                q1 += q1 & 1;
+        }
+    }
+    ix0 = (q >> 1) + 0x3fe00000;
+    ix1 = q1 >> 1;
+    if (q & 1)
+        ix1 |= sign;
+    ix = ix0 + ((unsigned int)m << 20);
+    ix <<= 32;
+    ix |= ix1;
+    return *(double*)&ix;
 }
 
 /*********************************************************************




More information about the wine-cvs mailing list