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