Просмотр исходного кода

LibC strtod: Reduce incremental error to nearly nothing

Instead of scaling by 1/10th N times, scale 10^N and then divide by
that. Avoid doing this beyond double-infinity. This decreases the
progressive error for numbers outside of integer range immensely. Not
a full 100% fix; there is still a single ULP difference detected by a
Javascript test
Peter Bindels 4 лет назад
Родитель
Сommit
0a0089fc11
1 измененных файлов с 9 добавлено и 2 удалено
  1. 9 2
      Userland/Libraries/LibC/stdlib.cpp

+ 9 - 2
Userland/Libraries/LibC/stdlib.cpp

@@ -646,9 +646,15 @@ double strtod(const char* str, char** endptr)
 
     // TODO: If `exponent` is large, this could be made faster.
     double value = digits.number();
+    double scale = 1;
+
     if (exponent < 0) {
         exponent = -exponent;
-        for (int i = 0; i < exponent; ++i) {
+        for (int i = 0; i < min(exponent, 300); ++i) {
+            scale *= base;
+        }
+        value /= scale;
+        for (int i = 300; i < exponent; i++) {
             value /= base;
         }
         if (value == -0.0 || value == +0.0) {
@@ -656,8 +662,9 @@ double strtod(const char* str, char** endptr)
         }
     } else if (exponent > 0) {
         for (int i = 0; i < exponent; ++i) {
-            value *= base;
+            scale *= base;
         }
+        value *= scale;
         if (value == -__builtin_huge_val() || value == +__builtin_huge_val()) {
             errno = ERANGE;
         }