Index: src/strtod.cc |
diff --git a/src/strtod.cc b/src/strtod.cc |
index 68444fc85179b0eed10534019ca8824de6e44258..9af2fc31f34de52536eee0b47847e940066c451c 100644 |
--- a/src/strtod.cc |
+++ b/src/strtod.cc |
@@ -85,12 +85,22 @@ static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); |
extern "C" double gay_strtod(const char* s00, const char** se); |
static double old_strtod(Vector<const char> buffer, int exponent) { |
+ // gay_strtod is broken on Linux,x86. For numbers with few decimal digits |
+ // the computation is done using floating-point operations which (on Linux) |
+ // are prone to double-rounding errors. |
+ // By adding several zeroes to the buffer gay_strtod falls back to a slower |
+ // (but correct) algorithm. |
+ const int kInsertedZeroesCount = 20; |
char gay_buffer[1024]; |
Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer)); |
int pos = 0; |
for (int i = 0; i < buffer.length(); ++i) { |
gay_buffer_vector[pos++] = buffer[i]; |
} |
+ for (int i = 0; i < kInsertedZeroesCount; ++i) { |
+ gay_buffer_vector[pos++] = '0'; |
+ } |
+ exponent -= kInsertedZeroesCount; |
gay_buffer_vector[pos++] = 'e'; |
if (exponent < 0) { |
gay_buffer_vector[pos++] = '-'; |
@@ -139,13 +149,16 @@ uint64_t ReadUint64(Vector<const char> buffer) { |
} |
-double Strtod(Vector<const char> buffer, int exponent) { |
- Vector<const char> left_trimmed = TrimLeadingZeros(buffer); |
- Vector<const char> trimmed = TrimTrailingZeros(left_trimmed); |
- exponent += left_trimmed.length() - trimmed.length(); |
- if (trimmed.length() == 0) return 0.0; |
- if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY; |
- if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0; |
+static bool DoubleStrtod(Vector<const char> trimmed, |
+ int exponent, |
+ double* result) { |
+#if defined(V8_TARGET_ARCH_IA32) && !defined(WIN32) |
+ // On x86 the floating-point stack can be 64 or 80 bits wide. If it is |
+ // 80 bits wide (as is the case on Linux) then double-rounding occurs and the |
+ // result is not accurate. |
+ // We know that Windows32 uses 64 bits and is therefore accurate. |
+ return false; |
+#endif |
if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { |
// The trimmed input fits into a double. |
// If the 10^exponent (resp. 10^-exponent) fits into a double too then we |
@@ -155,13 +168,15 @@ double Strtod(Vector<const char> buffer, int exponent) { |
// return the best possible approximation. |
if (exponent < 0 && -exponent < kExactPowersOfTenSize) { |
// 10^-exponent fits into a double. |
- double buffer_d = static_cast<double>(ReadUint64(trimmed)); |
- return buffer_d / exact_powers_of_ten[-exponent]; |
+ *result = static_cast<double>(ReadUint64(trimmed)); |
+ *result /= exact_powers_of_ten[-exponent]; |
+ return true; |
} |
if (0 <= exponent && exponent < kExactPowersOfTenSize) { |
// 10^exponent fits into a double. |
- double buffer_d = static_cast<double>(ReadUint64(trimmed)); |
- return buffer_d * exact_powers_of_ten[exponent]; |
+ *result = static_cast<double>(ReadUint64(trimmed)); |
+ *result *= exact_powers_of_ten[exponent]; |
+ return true; |
} |
int remaining_digits = |
kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); |
@@ -170,11 +185,27 @@ double Strtod(Vector<const char> buffer, int exponent) { |
// The trimmed string was short and we can multiply it with |
// 10^remaining_digits. As a result the remaining exponent now fits |
// into a double too. |
- double buffer_d = static_cast<double>(ReadUint64(trimmed)); |
- buffer_d *= exact_powers_of_ten[remaining_digits]; |
- return buffer_d * exact_powers_of_ten[exponent - remaining_digits]; |
+ *result = static_cast<double>(ReadUint64(trimmed)); |
+ *result *= exact_powers_of_ten[remaining_digits]; |
+ *result *= exact_powers_of_ten[exponent - remaining_digits]; |
+ return true; |
} |
} |
+ return false; |
+} |
+ |
+ |
+double Strtod(Vector<const char> buffer, int exponent) { |
+ Vector<const char> left_trimmed = TrimLeadingZeros(buffer); |
+ Vector<const char> trimmed = TrimTrailingZeros(left_trimmed); |
+ exponent += left_trimmed.length() - trimmed.length(); |
+ if (trimmed.length() == 0) return 0.0; |
+ if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY; |
+ if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0; |
+ double result; |
+ if (DoubleStrtod(trimmed, exponent, &result)) { |
+ return result; |
+ } |
return old_strtod(trimmed, exponent); |
} |