Piotr Caban : msvcrt: Fix rounding of numbers smaller than minimal subnormal.

Alexandre Julliard julliard at winehq.org
Thu Jul 23 16:36:57 CDT 2020


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

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Thu Jul 23 15:38:46 2020 +0200

msvcrt: Fix rounding of numbers smaller than minimal subnormal.

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

---

 dlls/msvcrt/string.c         | 28 +++++++++++++++-------------
 dlls/ucrtbase/tests/string.c |  2 ++
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 5b6d73626a..ab6747db5c 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -413,25 +413,21 @@ int fpnum_double(struct fpnum *fp, double *d)
         fp->m >>= 1;
         fp->exp++;
     }
-
-    /* handle subnormal that falls into regular range due to rounding */
     fp->exp += (1 << (EXP_BITS-1)) - 1;
-    if (!fp->exp && (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1)))
-    {
-        if (fp->m + 1 >= (ULONGLONG)1 << MANT_BITS)
-        {
-            fp->m++;
-            fp->m >>= 1;
-            fp->exp++;
-            fp->mod = FP_ROUND_DOWN;
-        }
-    }
 
     /* handle subnormals */
     if (fp->exp <= 0)
+    {
+        if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
+        else if (fp->m & 1) fp->mod = FP_ROUND_UP;
+        else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
         fp->m >>= 1;
+    }
     while(fp->m && fp->exp<0)
     {
+        if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
+        else if (fp->m & 1) fp->mod = FP_ROUND_UP;
+        else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
         fp->m >>= 1;
         fp->exp++;
     }
@@ -440,7 +436,13 @@ int fpnum_double(struct fpnum *fp, double *d)
     if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
     {
         fp->m++;
-        if (fp->m >= (ULONGLONG)1 << MANT_BITS)
+
+        /* handle subnormal that falls into regular range due to rounding */
+        if (fp->m == (ULONGLONG)1 << (MANT_BITS - 1))
+        {
+            fp->exp++;
+        }
+        else if (fp->m >= (ULONGLONG)1 << MANT_BITS)
         {
             fp->exp++;
             fp->m >>= 1;
diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c
index 5857a02773..3a4b8b9f04 100644
--- a/dlls/ucrtbase/tests/string.c
+++ b/dlls/ucrtbase/tests/string.c
@@ -148,6 +148,8 @@ static void test_strtod(void)
     test_strtod_str("1.7976931348623158e+308", 1.7976931348623158e+308, 23);
     test_strtod_str("2.2250738585072014e-308", 2.2250738585072014e-308, 23);
     test_strtod_str("4.9406564584124654e-324", 4.9406564584124654e-324, 23);
+    test_strtod_str("2.48e-324", 4.9406564584124654e-324, 9);
+    test_strtod_str_errno("2.47e-324", 0, 9, ERANGE);
 }
 
 static void test__memicmp(void)




More information about the wine-cvs mailing list