Alexandre Julliard : ntdll: Copy sqrt() implementation from msvcrt.
Alexandre Julliard
julliard at winehq.org
Tue Oct 26 16:19:19 CDT 2021
Module: wine
Branch: master
Commit: 2e4c090c5ecac67908e3fb3290925503c358c38b
URL: https://source.winehq.org/git/wine.git/?a=commit;h=2e4c090c5ecac67908e3fb3290925503c358c38b
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Oct 26 10:34:06 2021 +0200
ntdll: Copy sqrt() implementation from msvcrt.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/math.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 132 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/math.c b/dlls/ntdll/math.c
index 3126f1d7b39..e6de9e67c1f 100644
--- a/dlls/ntdll/math.c
+++ b/dlls/ntdll/math.c
@@ -1047,6 +1047,37 @@ static inline int pow_checkint(UINT64 iy)
return 2;
}
+/* Copied from musl: src/math/__fpclassify.c */
+static short _dclass(double x)
+{
+ union { double f; UINT64 i; } u = { x };
+ int e = u.i >> 52 & 0x7ff;
+
+ if (!e) return u.i << 1 ? FP_SUBNORMAL : FP_ZERO;
+ if (e == 0x7ff) return (u.i << 12) ? FP_NAN : FP_INFINITE;
+ return FP_NORMAL;
+}
+
+static BOOL sqrt_validate( double *x, BOOL update_sw )
+{
+ short c = _dclass(*x);
+
+ if (c == FP_ZERO) return FALSE;
+ if (c == FP_NAN)
+ {
+ /* set signaling bit */
+ *(ULONGLONG*)x |= 0x8000000000000ULL;
+ return FALSE;
+ }
+ if (signbit(*x))
+ {
+ *x = -NAN;
+ return FALSE;
+ }
+ if (c == FP_INFINITE) return FALSE;
+ return TRUE;
+}
+
/*********************************************************************
* abs (NTDLL.@)
@@ -1756,10 +1787,109 @@ double CDECL sin( double x )
/*********************************************************************
* sqrt (NTDLL.@)
+ *
+ * Copied from musl: src/math/sqrt.c
*/
-double CDECL sqrt( double d )
+double CDECL sqrt( double x )
{
- return unix_funcs->sqrt( d );
+ 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;
+
+ if (!sqrt_validate(&x, TRUE))
+ return x;
+
+ ix = *(ULONGLONG*)&x;
+ ix0 = ix >> 32;
+ ix1 = ix;
+
+ /* 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