Call StrtodTrimmed/StrtofTrimmed from StringToDoubleConverter::StringToIeee. (#154)
We know the buffer contains no leading zeros and less than kMaxSignificantDecimalDigits, so we only need to trim trailing zeros and can then call Strto*Trimmed, which is quite a bit faster.
diff --git a/double-conversion/string-to-double.cc b/double-conversion/string-to-double.cc
index 03ad670..85c3a08 100644
--- a/double-conversion/string-to-double.cc
+++ b/double-conversion/string-to-double.cc
@@ -729,11 +729,17 @@
DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
buffer[buffer_pos] = '\0';
+ // Code above ensures there are no leading zeros and the buffer has fewer than
+ // kMaxSignificantDecimalDigits characters. Trim trailing zeros.
+ Vector<const char> chars(buffer, buffer_pos);
+ chars = TrimTrailingZeros(chars);
+ exponent += buffer_pos - chars.length();
+
double converted;
if (read_as_double) {
- converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+ converted = StrtodTrimmed(chars, exponent);
} else {
- converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
+ converted = StrtofTrimmed(chars, exponent);
}
*processed_characters_count = static_cast<int>(current - input);
return sign? -converted: converted;
diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc
index 24fd859..0cc7495 100644
--- a/double-conversion/strtod.cc
+++ b/double-conversion/strtod.cc
@@ -101,17 +101,6 @@
return Vector<const char>(buffer.start(), 0);
}
-
-static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
- for (int i = buffer.length() - 1; i >= 0; --i) {
- if (buffer[i] != '0') {
- return buffer.SubVector(0, i + 1);
- }
- }
- return Vector<const char>(buffer.start(), 0);
-}
-
-
static void CutToMaxSignificantDigits(Vector<const char> buffer,
int exponent,
char* significant_buffer,
@@ -536,6 +525,12 @@
TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
&trimmed, &updated_exponent);
exponent = updated_exponent;
+ return StrtofTrimmed(trimmed, exponent);
+}
+
+float StrtofTrimmed(Vector<const char> trimmed, int exponent) {
+ DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
+ DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
double double_guess;
bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
diff --git a/double-conversion/strtod.h b/double-conversion/strtod.h
index ff0ee47..77221fb 100644
--- a/double-conversion/strtod.h
+++ b/double-conversion/strtod.h
@@ -40,11 +40,25 @@
// contain a dot or a sign. It must not start with '0', and must not be empty.
float Strtof(Vector<const char> buffer, int exponent);
-// For special use cases, the heart of the Strtod() function is also available
-// separately, it assumes that 'trimmed' is as produced by TrimAndCut(), i.e.
-// no leading or trailing zeros, also no lone zero, and not 'too many' digits.
+// Same as Strtod, but assumes that 'trimmed' is already trimmed, as if run
+// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
+// zeros, must not be a lone zero, and must not have 'too many' digits.
double StrtodTrimmed(Vector<const char> trimmed, int exponent);
+// Same as Strtof, but assumes that 'trimmed' is already trimmed, as if run
+// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
+// zeros, must not be a lone zero, and must not have 'too many' digits.
+float StrtofTrimmed(Vector<const char> trimmed, int exponent);
+
+inline Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
+ for (int i = buffer.length() - 1; i >= 0; --i) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(0, i + 1);
+ }
+ }
+ return Vector<const char>(buffer.start(), 0);
+}
+
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_STRTOD_H_
diff --git a/test/cctest/test-strtod.cc b/test/cctest/test-strtod.cc
index d1295aa..b5a3bab 100644
--- a/test/cctest/test-strtod.cc
+++ b/test/cctest/test-strtod.cc
@@ -55,6 +55,10 @@
return Strtof(StringToVector(str), exponent);
}
+static float StrtofTrimmedChar(const char* str, int exponent) {
+ return StrtofTrimmed(StringToVector(str), exponent);
+}
+
TEST(Strtod) {
Vector<const char> vector;
@@ -876,6 +880,194 @@
}
+TEST(StrtofTrimmed) {
+ Vector<const char> vector;
+
+ vector = StringToVector("1");
+ CHECK_EQ(1.0f, StrtofTrimmed(vector, 0));
+ CHECK_EQ(10.0f, StrtofTrimmed(vector, 1));
+ CHECK_EQ(100.0f, StrtofTrimmed(vector, 2));
+ CHECK_EQ(1e20f, StrtofTrimmed(vector, 20));
+ CHECK_EQ(1e22f, StrtofTrimmed(vector, 22));
+ CHECK_EQ(1e23f, StrtofTrimmed(vector, 23));
+ CHECK_EQ(1e35f, StrtofTrimmed(vector, 35));
+ CHECK_EQ(1e36f, StrtofTrimmed(vector, 36));
+ CHECK_EQ(1e37f, StrtofTrimmed(vector, 37));
+ CHECK_EQ(1e-1f, StrtofTrimmed(vector, -1));
+ CHECK_EQ(1e-2f, StrtofTrimmed(vector, -2));
+ CHECK_EQ(1e-5f, StrtofTrimmed(vector, -5));
+ CHECK_EQ(1e-20f, StrtofTrimmed(vector, -20));
+ CHECK_EQ(1e-22f, StrtofTrimmed(vector, -22));
+ CHECK_EQ(1e-23f, StrtofTrimmed(vector, -23));
+ CHECK_EQ(1e-25f, StrtofTrimmed(vector, -25));
+ CHECK_EQ(1e-39f, StrtofTrimmed(vector, -39));
+
+ vector = StringToVector("2");
+ CHECK_EQ(2.0f, StrtofTrimmed(vector, 0));
+ CHECK_EQ(20.0f, StrtofTrimmed(vector, 1));
+ CHECK_EQ(200.0f, StrtofTrimmed(vector, 2));
+ CHECK_EQ(2e20f, StrtofTrimmed(vector, 20));
+ CHECK_EQ(2e22f, StrtofTrimmed(vector, 22));
+ CHECK_EQ(2e23f, StrtofTrimmed(vector, 23));
+ CHECK_EQ(2e35f, StrtofTrimmed(vector, 35));
+ CHECK_EQ(2e36f, StrtofTrimmed(vector, 36));
+ CHECK_EQ(2e37f, StrtofTrimmed(vector, 37));
+ CHECK_EQ(2e-1f, StrtofTrimmed(vector, -1));
+ CHECK_EQ(2e-2f, StrtofTrimmed(vector, -2));
+ CHECK_EQ(2e-5f, StrtofTrimmed(vector, -5));
+ CHECK_EQ(2e-20f, StrtofTrimmed(vector, -20));
+ CHECK_EQ(2e-22f, StrtofTrimmed(vector, -22));
+ CHECK_EQ(2e-23f, StrtofTrimmed(vector, -23));
+ CHECK_EQ(2e-25f, StrtofTrimmed(vector, -25));
+ CHECK_EQ(2e-39f, StrtofTrimmed(vector, -39));
+
+ vector = StringToVector("9");
+ CHECK_EQ(9.0f, StrtofTrimmed(vector, 0));
+ CHECK_EQ(90.0f, StrtofTrimmed(vector, 1));
+ CHECK_EQ(900.0f, StrtofTrimmed(vector, 2));
+ CHECK_EQ(9e20f, StrtofTrimmed(vector, 20));
+ CHECK_EQ(9e22f, StrtofTrimmed(vector, 22));
+ CHECK_EQ(9e23f, StrtofTrimmed(vector, 23));
+ CHECK_EQ(9e35f, StrtofTrimmed(vector, 35));
+ CHECK_EQ(9e36f, StrtofTrimmed(vector, 36));
+ CHECK_EQ(9e37f, StrtofTrimmed(vector, 37));
+ CHECK_EQ(9e-1f, StrtofTrimmed(vector, -1));
+ CHECK_EQ(9e-2f, StrtofTrimmed(vector, -2));
+ CHECK_EQ(9e-5f, StrtofTrimmed(vector, -5));
+ CHECK_EQ(9e-20f, StrtofTrimmed(vector, -20));
+ CHECK_EQ(9e-22f, StrtofTrimmed(vector, -22));
+ CHECK_EQ(9e-23f, StrtofTrimmed(vector, -23));
+ CHECK_EQ(9e-25f, StrtofTrimmed(vector, -25));
+ CHECK_EQ(9e-39f, StrtofTrimmed(vector, -39));
+
+ vector = StringToVector("12345");
+ CHECK_EQ(12345.0f, StrtofTrimmed(vector, 0));
+ CHECK_EQ(123450.0f, StrtofTrimmed(vector, 1));
+ CHECK_EQ(1234500.0f, StrtofTrimmed(vector, 2));
+ CHECK_EQ(12345e20f, StrtofTrimmed(vector, 20));
+ CHECK_EQ(12345e22f, StrtofTrimmed(vector, 22));
+ CHECK_EQ(12345e23f, StrtofTrimmed(vector, 23));
+ CHECK_EQ(12345e30f, StrtofTrimmed(vector, 30));
+ CHECK_EQ(12345e31f, StrtofTrimmed(vector, 31));
+ CHECK_EQ(12345e32f, StrtofTrimmed(vector, 32));
+ CHECK_EQ(12345e-1f, StrtofTrimmed(vector, -1));
+ CHECK_EQ(12345e-2f, StrtofTrimmed(vector, -2));
+ CHECK_EQ(12345e-5f, StrtofTrimmed(vector, -5));
+ CHECK_EQ(12345e-20f, StrtofTrimmed(vector, -20));
+ CHECK_EQ(12345e-22f, StrtofTrimmed(vector, -22));
+ CHECK_EQ(12345e-23f, StrtofTrimmed(vector, -23));
+ CHECK_EQ(12345e-25f, StrtofTrimmed(vector, -25));
+ CHECK_EQ(12345e-39f, StrtofTrimmed(vector, -39));
+
+ vector = StringToVector("12345678901234");
+ CHECK_EQ(12345678901234.0f, StrtofTrimmed(vector, 0));
+ CHECK_EQ(123456789012340.0f, StrtofTrimmed(vector, 1));
+ CHECK_EQ(1234567890123400.0f, StrtofTrimmed(vector, 2));
+ CHECK_EQ(12345678901234e20f, StrtofTrimmed(vector, 20));
+ CHECK_EQ(12345678901234e22f, StrtofTrimmed(vector, 22));
+ CHECK_EQ(12345678901234e23f, StrtofTrimmed(vector, 23));
+ CHECK_EQ(12345678901234e-1f, StrtofTrimmed(vector, -1));
+ CHECK_EQ(12345678901234e-2f, StrtofTrimmed(vector, -2));
+ CHECK_EQ(12345678901234e-5f, StrtofTrimmed(vector, -5));
+ CHECK_EQ(12345678901234e-20f, StrtofTrimmed(vector, -20));
+ CHECK_EQ(12345678901234e-22f, StrtofTrimmed(vector, -22));
+ CHECK_EQ(12345678901234e-23f, StrtofTrimmed(vector, -23));
+ CHECK_EQ(12345678901234e-25f, StrtofTrimmed(vector, -25));
+ CHECK_EQ(12345678901234e-39f, StrtofTrimmed(vector, -39));
+
+ vector = StringToVector("123456789012345");
+ CHECK_EQ(123456789012345.0f, StrtofTrimmed(vector, 0));
+ CHECK_EQ(1234567890123450.0f, StrtofTrimmed(vector, 1));
+ CHECK_EQ(12345678901234500.0f, StrtofTrimmed(vector, 2));
+ CHECK_EQ(123456789012345e20f, StrtofTrimmed(vector, 20));
+ CHECK_EQ(123456789012345e22f, StrtofTrimmed(vector, 22));
+ CHECK_EQ(123456789012345e23f, StrtofTrimmed(vector, 23));
+ CHECK_EQ(123456789012345e-1f, StrtofTrimmed(vector, -1));
+ CHECK_EQ(123456789012345e-2f, StrtofTrimmed(vector, -2));
+ CHECK_EQ(123456789012345e-5f, StrtofTrimmed(vector, -5));
+ CHECK_EQ(123456789012345e-20f, StrtofTrimmed(vector, -20));
+ CHECK_EQ(123456789012345e-22f, StrtofTrimmed(vector, -22));
+ CHECK_EQ(123456789012345e-23f, StrtofTrimmed(vector, -23));
+ CHECK_EQ(123456789012345e-25f, StrtofTrimmed(vector, -25));
+ CHECK_EQ(123456789012345e-39f, StrtofTrimmed(vector, -39));
+
+ CHECK_EQ(0.0f, StrtofTrimmedChar("", 1324));
+ CHECK_EQ(0.0f, StrtofTrimmedChar("2", -324));
+ CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45));
+ // It would be more readable to put non-zero literals on the left side (i.e.
+ // CHECK_EQ(1e-46, StrtofChar("1", -45))), but then Gcc complains that
+ // they are truncated to zero.
+ CHECK_EQ(0.0f, StrtofTrimmedChar("1", -46));
+ CHECK_EQ(0.0f, StrtofTrimmedChar("1", -47));
+ CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45));
+ CHECK_EQ(1e-45f, StrtofTrimmedChar("8", -46));
+
+ // It would be more readable to put the literals (and not Double::Infinity())
+ // on the left side (i.e. CHECK_EQ(3e38, StrtofChar("3", 38))), but then Gcc
+ // complains that the floating constant exceeds range of 'double'.
+ CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("3", 39));
+ CHECK_EQ(3e38f, StrtofTrimmedChar("3", 38));
+ CHECK_EQ(3401e35f, StrtofTrimmedChar("3401", 35));
+ CHECK_EQ(3401e34f, StrtofTrimmedChar("3401", 34));
+ CHECK_EQ(34e37f, StrtofTrimmedChar("34", 37));
+ CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235676", 28));
+ CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235677", 28));
+ CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("34028235678", 28));
+
+ // The following number is the result of 89255.0/1e-22. Both floating-point
+ // numbers can be accurately represented with doubles. However on Linux,x86
+ // the floating-point stack is set to 80bits and the double-rounding
+ // introduces an error.
+ CHECK_EQ(89255e-22f, StrtofTrimmedChar("89255", -22));
+
+ // Boundary cases. Boundaries themselves should round to even.
+ //
+ // 0x4f012334 = 2166567936
+ // next: 2166568192
+ // boundary: 2166568064 should round down.
+ CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166567936", 0));
+ CHECK_EQ(2166568192.0f, StrtofTrimmedChar("2166568192", 0));
+ CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166568064", 0));
+ CHECK_EQ(2166567936.0f, StrtofTrimmedChar("216656806399999", -5));
+ CHECK_EQ(2166568192.0f, StrtofTrimmedChar("216656806400001", -5));
+ // Verify that we don't double round.
+ // Get the boundary of the boundary.
+ CHECK_EQ(2.1665680640000002384185791015625e9, 2166568064.0);
+ // Visual Studio gets this wrong and believes that these two numbers are the
+ // same doubles. We want to test our conversion and not the compiler. We
+ // therefore disable the check.
+#ifndef _MSC_VER
+ CHECK(2.16656806400000023841857910156251e9 != 2166568064.0);
+#endif
+ CHECK_EQ(2166568192.0f, StrtofTrimmedChar("21665680640000002384185791015625", -22));
+
+ // 0x4fffffff = 8589934080
+ // next: 8589934592
+ // boundary: 8589934336 should round up.
+ CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934592", 0));
+ CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934336", 0));
+ CHECK_EQ(8589934080.0f, StrtofTrimmedChar("858993433599999", -5));
+ CHECK_EQ(8589934592.0f, StrtofTrimmedChar("858993433600001", -5));
+ // Verify that we don't double round.
+ // Get the boundary of the boundary.
+ // Visual Studio gets this wrong. To avoid failing tests because of a broken
+ // compiler we disable the following two tests. They were only testing the
+ // compiler. The real test is still active.
+#ifndef _MSC_VER
+ CHECK_EQ(8.589934335999999523162841796875e+09, 8589934336.0);
+ CHECK(8.5899343359999995231628417968749e+09 != 8589934336.0);
+#endif
+ CHECK_EQ(8589934080.0f, StrtofTrimmedChar("8589934335999999523162841796875", -21));
+
+ // 0x4f000000 = 2147483648
+ // next: 2147483904
+ // boundary: 2147483776 should round down.
+ CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483648", 0));
+ CHECK_EQ(2147483904.0f, StrtofTrimmedChar("2147483904", 0));
+ CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483776", 0));
+ CHECK_EQ(2147483648.0f, StrtofTrimmedChar("214748377599999", -5));
+ CHECK_EQ(2147483904.0f, StrtofTrimmedChar("214748377600001", -5));
+}
static int CompareBignumToDiyFp(const Bignum& bignum_digits,
int bignum_exponent,