Skip to content

Commit af900a7

Browse files
authored
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.
1 parent 95c7131 commit af900a7

4 files changed

Lines changed: 223 additions & 16 deletions

File tree

double-conversion/string-to-double.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,11 +729,17 @@ double StringToDoubleConverter::StringToIeee(
729729
DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
730730
buffer[buffer_pos] = '\0';
731731

732+
// Code above ensures there are no leading zeros and the buffer has fewer than
733+
// kMaxSignificantDecimalDigits characters. Trim trailing zeros.
734+
Vector<const char> chars(buffer, buffer_pos);
735+
chars = TrimTrailingZeros(chars);
736+
exponent += buffer_pos - chars.length();
737+
732738
double converted;
733739
if (read_as_double) {
734-
converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
740+
converted = StrtodTrimmed(chars, exponent);
735741
} else {
736-
converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
742+
converted = StrtofTrimmed(chars, exponent);
737743
}
738744
*processed_characters_count = static_cast<int>(current - input);
739745
return sign? -converted: converted;

double-conversion/strtod.cc

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,6 @@ static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
101101
return Vector<const char>(buffer.start(), 0);
102102
}
103103

104-
105-
static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
106-
for (int i = buffer.length() - 1; i >= 0; --i) {
107-
if (buffer[i] != '0') {
108-
return buffer.SubVector(0, i + 1);
109-
}
110-
}
111-
return Vector<const char>(buffer.start(), 0);
112-
}
113-
114-
115104
static void CutToMaxSignificantDigits(Vector<const char> buffer,
116105
int exponent,
117106
char* significant_buffer,
@@ -536,6 +525,12 @@ float Strtof(Vector<const char> buffer, int exponent) {
536525
TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
537526
&trimmed, &updated_exponent);
538527
exponent = updated_exponent;
528+
return StrtofTrimmed(trimmed, exponent);
529+
}
530+
531+
float StrtofTrimmed(Vector<const char> trimmed, int exponent) {
532+
DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
533+
DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
539534

540535
double double_guess;
541536
bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);

double-conversion/strtod.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,25 @@ double Strtod(Vector<const char> buffer, int exponent);
4040
// contain a dot or a sign. It must not start with '0', and must not be empty.
4141
float Strtof(Vector<const char> buffer, int exponent);
4242

43-
// For special use cases, the heart of the Strtod() function is also available
44-
// separately, it assumes that 'trimmed' is as produced by TrimAndCut(), i.e.
45-
// no leading or trailing zeros, also no lone zero, and not 'too many' digits.
43+
// Same as Strtod, but assumes that 'trimmed' is already trimmed, as if run
44+
// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
45+
// zeros, must not be a lone zero, and must not have 'too many' digits.
4646
double StrtodTrimmed(Vector<const char> trimmed, int exponent);
4747

48+
// Same as Strtof, but assumes that 'trimmed' is already trimmed, as if run
49+
// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
50+
// zeros, must not be a lone zero, and must not have 'too many' digits.
51+
float StrtofTrimmed(Vector<const char> trimmed, int exponent);
52+
53+
inline Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
54+
for (int i = buffer.length() - 1; i >= 0; --i) {
55+
if (buffer[i] != '0') {
56+
return buffer.SubVector(0, i + 1);
57+
}
58+
}
59+
return Vector<const char>(buffer.start(), 0);
60+
}
61+
4862
} // namespace double_conversion
4963

5064
#endif // DOUBLE_CONVERSION_STRTOD_H_

test/cctest/test-strtod.cc

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ static float StrtofChar(const char* str, int exponent) {
5555
return Strtof(StringToVector(str), exponent);
5656
}
5757

58+
static float StrtofTrimmedChar(const char* str, int exponent) {
59+
return StrtofTrimmed(StringToVector(str), exponent);
60+
}
61+
5862

5963
TEST(Strtod) {
6064
Vector<const char> vector;
@@ -876,6 +880,194 @@ TEST(Strtof) {
876880

877881
}
878882

883+
TEST(StrtofTrimmed) {
884+
Vector<const char> vector;
885+
886+
vector = StringToVector("1");
887+
CHECK_EQ(1.0f, StrtofTrimmed(vector, 0));
888+
CHECK_EQ(10.0f, StrtofTrimmed(vector, 1));
889+
CHECK_EQ(100.0f, StrtofTrimmed(vector, 2));
890+
CHECK_EQ(1e20f, StrtofTrimmed(vector, 20));
891+
CHECK_EQ(1e22f, StrtofTrimmed(vector, 22));
892+
CHECK_EQ(1e23f, StrtofTrimmed(vector, 23));
893+
CHECK_EQ(1e35f, StrtofTrimmed(vector, 35));
894+
CHECK_EQ(1e36f, StrtofTrimmed(vector, 36));
895+
CHECK_EQ(1e37f, StrtofTrimmed(vector, 37));
896+
CHECK_EQ(1e-1f, StrtofTrimmed(vector, -1));
897+
CHECK_EQ(1e-2f, StrtofTrimmed(vector, -2));
898+
CHECK_EQ(1e-5f, StrtofTrimmed(vector, -5));
899+
CHECK_EQ(1e-20f, StrtofTrimmed(vector, -20));
900+
CHECK_EQ(1e-22f, StrtofTrimmed(vector, -22));
901+
CHECK_EQ(1e-23f, StrtofTrimmed(vector, -23));
902+
CHECK_EQ(1e-25f, StrtofTrimmed(vector, -25));
903+
CHECK_EQ(1e-39f, StrtofTrimmed(vector, -39));
904+
905+
vector = StringToVector("2");
906+
CHECK_EQ(2.0f, StrtofTrimmed(vector, 0));
907+
CHECK_EQ(20.0f, StrtofTrimmed(vector, 1));
908+
CHECK_EQ(200.0f, StrtofTrimmed(vector, 2));
909+
CHECK_EQ(2e20f, StrtofTrimmed(vector, 20));
910+
CHECK_EQ(2e22f, StrtofTrimmed(vector, 22));
911+
CHECK_EQ(2e23f, StrtofTrimmed(vector, 23));
912+
CHECK_EQ(2e35f, StrtofTrimmed(vector, 35));
913+
CHECK_EQ(2e36f, StrtofTrimmed(vector, 36));
914+
CHECK_EQ(2e37f, StrtofTrimmed(vector, 37));
915+
CHECK_EQ(2e-1f, StrtofTrimmed(vector, -1));
916+
CHECK_EQ(2e-2f, StrtofTrimmed(vector, -2));
917+
CHECK_EQ(2e-5f, StrtofTrimmed(vector, -5));
918+
CHECK_EQ(2e-20f, StrtofTrimmed(vector, -20));
919+
CHECK_EQ(2e-22f, StrtofTrimmed(vector, -22));
920+
CHECK_EQ(2e-23f, StrtofTrimmed(vector, -23));
921+
CHECK_EQ(2e-25f, StrtofTrimmed(vector, -25));
922+
CHECK_EQ(2e-39f, StrtofTrimmed(vector, -39));
923+
924+
vector = StringToVector("9");
925+
CHECK_EQ(9.0f, StrtofTrimmed(vector, 0));
926+
CHECK_EQ(90.0f, StrtofTrimmed(vector, 1));
927+
CHECK_EQ(900.0f, StrtofTrimmed(vector, 2));
928+
CHECK_EQ(9e20f, StrtofTrimmed(vector, 20));
929+
CHECK_EQ(9e22f, StrtofTrimmed(vector, 22));
930+
CHECK_EQ(9e23f, StrtofTrimmed(vector, 23));
931+
CHECK_EQ(9e35f, StrtofTrimmed(vector, 35));
932+
CHECK_EQ(9e36f, StrtofTrimmed(vector, 36));
933+
CHECK_EQ(9e37f, StrtofTrimmed(vector, 37));
934+
CHECK_EQ(9e-1f, StrtofTrimmed(vector, -1));
935+
CHECK_EQ(9e-2f, StrtofTrimmed(vector, -2));
936+
CHECK_EQ(9e-5f, StrtofTrimmed(vector, -5));
937+
CHECK_EQ(9e-20f, StrtofTrimmed(vector, -20));
938+
CHECK_EQ(9e-22f, StrtofTrimmed(vector, -22));
939+
CHECK_EQ(9e-23f, StrtofTrimmed(vector, -23));
940+
CHECK_EQ(9e-25f, StrtofTrimmed(vector, -25));
941+
CHECK_EQ(9e-39f, StrtofTrimmed(vector, -39));
942+
943+
vector = StringToVector("12345");
944+
CHECK_EQ(12345.0f, StrtofTrimmed(vector, 0));
945+
CHECK_EQ(123450.0f, StrtofTrimmed(vector, 1));
946+
CHECK_EQ(1234500.0f, StrtofTrimmed(vector, 2));
947+
CHECK_EQ(12345e20f, StrtofTrimmed(vector, 20));
948+
CHECK_EQ(12345e22f, StrtofTrimmed(vector, 22));
949+
CHECK_EQ(12345e23f, StrtofTrimmed(vector, 23));
950+
CHECK_EQ(12345e30f, StrtofTrimmed(vector, 30));
951+
CHECK_EQ(12345e31f, StrtofTrimmed(vector, 31));
952+
CHECK_EQ(12345e32f, StrtofTrimmed(vector, 32));
953+
CHECK_EQ(12345e-1f, StrtofTrimmed(vector, -1));
954+
CHECK_EQ(12345e-2f, StrtofTrimmed(vector, -2));
955+
CHECK_EQ(12345e-5f, StrtofTrimmed(vector, -5));
956+
CHECK_EQ(12345e-20f, StrtofTrimmed(vector, -20));
957+
CHECK_EQ(12345e-22f, StrtofTrimmed(vector, -22));
958+
CHECK_EQ(12345e-23f, StrtofTrimmed(vector, -23));
959+
CHECK_EQ(12345e-25f, StrtofTrimmed(vector, -25));
960+
CHECK_EQ(12345e-39f, StrtofTrimmed(vector, -39));
961+
962+
vector = StringToVector("12345678901234");
963+
CHECK_EQ(12345678901234.0f, StrtofTrimmed(vector, 0));
964+
CHECK_EQ(123456789012340.0f, StrtofTrimmed(vector, 1));
965+
CHECK_EQ(1234567890123400.0f, StrtofTrimmed(vector, 2));
966+
CHECK_EQ(12345678901234e20f, StrtofTrimmed(vector, 20));
967+
CHECK_EQ(12345678901234e22f, StrtofTrimmed(vector, 22));
968+
CHECK_EQ(12345678901234e23f, StrtofTrimmed(vector, 23));
969+
CHECK_EQ(12345678901234e-1f, StrtofTrimmed(vector, -1));
970+
CHECK_EQ(12345678901234e-2f, StrtofTrimmed(vector, -2));
971+
CHECK_EQ(12345678901234e-5f, StrtofTrimmed(vector, -5));
972+
CHECK_EQ(12345678901234e-20f, StrtofTrimmed(vector, -20));
973+
CHECK_EQ(12345678901234e-22f, StrtofTrimmed(vector, -22));
974+
CHECK_EQ(12345678901234e-23f, StrtofTrimmed(vector, -23));
975+
CHECK_EQ(12345678901234e-25f, StrtofTrimmed(vector, -25));
976+
CHECK_EQ(12345678901234e-39f, StrtofTrimmed(vector, -39));
977+
978+
vector = StringToVector("123456789012345");
979+
CHECK_EQ(123456789012345.0f, StrtofTrimmed(vector, 0));
980+
CHECK_EQ(1234567890123450.0f, StrtofTrimmed(vector, 1));
981+
CHECK_EQ(12345678901234500.0f, StrtofTrimmed(vector, 2));
982+
CHECK_EQ(123456789012345e20f, StrtofTrimmed(vector, 20));
983+
CHECK_EQ(123456789012345e22f, StrtofTrimmed(vector, 22));
984+
CHECK_EQ(123456789012345e23f, StrtofTrimmed(vector, 23));
985+
CHECK_EQ(123456789012345e-1f, StrtofTrimmed(vector, -1));
986+
CHECK_EQ(123456789012345e-2f, StrtofTrimmed(vector, -2));
987+
CHECK_EQ(123456789012345e-5f, StrtofTrimmed(vector, -5));
988+
CHECK_EQ(123456789012345e-20f, StrtofTrimmed(vector, -20));
989+
CHECK_EQ(123456789012345e-22f, StrtofTrimmed(vector, -22));
990+
CHECK_EQ(123456789012345e-23f, StrtofTrimmed(vector, -23));
991+
CHECK_EQ(123456789012345e-25f, StrtofTrimmed(vector, -25));
992+
CHECK_EQ(123456789012345e-39f, StrtofTrimmed(vector, -39));
993+
994+
CHECK_EQ(0.0f, StrtofTrimmedChar("", 1324));
995+
CHECK_EQ(0.0f, StrtofTrimmedChar("2", -324));
996+
CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45));
997+
// It would be more readable to put non-zero literals on the left side (i.e.
998+
// CHECK_EQ(1e-46, StrtofChar("1", -45))), but then Gcc complains that
999+
// they are truncated to zero.
1000+
CHECK_EQ(0.0f, StrtofTrimmedChar("1", -46));
1001+
CHECK_EQ(0.0f, StrtofTrimmedChar("1", -47));
1002+
CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45));
1003+
CHECK_EQ(1e-45f, StrtofTrimmedChar("8", -46));
1004+
1005+
// It would be more readable to put the literals (and not Double::Infinity())
1006+
// on the left side (i.e. CHECK_EQ(3e38, StrtofChar("3", 38))), but then Gcc
1007+
// complains that the floating constant exceeds range of 'double'.
1008+
CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("3", 39));
1009+
CHECK_EQ(3e38f, StrtofTrimmedChar("3", 38));
1010+
CHECK_EQ(3401e35f, StrtofTrimmedChar("3401", 35));
1011+
CHECK_EQ(3401e34f, StrtofTrimmedChar("3401", 34));
1012+
CHECK_EQ(34e37f, StrtofTrimmedChar("34", 37));
1013+
CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235676", 28));
1014+
CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235677", 28));
1015+
CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("34028235678", 28));
1016+
1017+
// The following number is the result of 89255.0/1e-22. Both floating-point
1018+
// numbers can be accurately represented with doubles. However on Linux,x86
1019+
// the floating-point stack is set to 80bits and the double-rounding
1020+
// introduces an error.
1021+
CHECK_EQ(89255e-22f, StrtofTrimmedChar("89255", -22));
1022+
1023+
// Boundary cases. Boundaries themselves should round to even.
1024+
//
1025+
// 0x4f012334 = 2166567936
1026+
// next: 2166568192
1027+
// boundary: 2166568064 should round down.
1028+
CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166567936", 0));
1029+
CHECK_EQ(2166568192.0f, StrtofTrimmedChar("2166568192", 0));
1030+
CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166568064", 0));
1031+
CHECK_EQ(2166567936.0f, StrtofTrimmedChar("216656806399999", -5));
1032+
CHECK_EQ(2166568192.0f, StrtofTrimmedChar("216656806400001", -5));
1033+
// Verify that we don't double round.
1034+
// Get the boundary of the boundary.
1035+
CHECK_EQ(2.1665680640000002384185791015625e9, 2166568064.0);
1036+
// Visual Studio gets this wrong and believes that these two numbers are the
1037+
// same doubles. We want to test our conversion and not the compiler. We
1038+
// therefore disable the check.
1039+
#ifndef _MSC_VER
1040+
CHECK(2.16656806400000023841857910156251e9 != 2166568064.0);
1041+
#endif
1042+
CHECK_EQ(2166568192.0f, StrtofTrimmedChar("21665680640000002384185791015625", -22));
1043+
1044+
// 0x4fffffff = 8589934080
1045+
// next: 8589934592
1046+
// boundary: 8589934336 should round up.
1047+
CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934592", 0));
1048+
CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934336", 0));
1049+
CHECK_EQ(8589934080.0f, StrtofTrimmedChar("858993433599999", -5));
1050+
CHECK_EQ(8589934592.0f, StrtofTrimmedChar("858993433600001", -5));
1051+
// Verify that we don't double round.
1052+
// Get the boundary of the boundary.
1053+
// Visual Studio gets this wrong. To avoid failing tests because of a broken
1054+
// compiler we disable the following two tests. They were only testing the
1055+
// compiler. The real test is still active.
1056+
#ifndef _MSC_VER
1057+
CHECK_EQ(8.589934335999999523162841796875e+09, 8589934336.0);
1058+
CHECK(8.5899343359999995231628417968749e+09 != 8589934336.0);
1059+
#endif
1060+
CHECK_EQ(8589934080.0f, StrtofTrimmedChar("8589934335999999523162841796875", -21));
1061+
1062+
// 0x4f000000 = 2147483648
1063+
// next: 2147483904
1064+
// boundary: 2147483776 should round down.
1065+
CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483648", 0));
1066+
CHECK_EQ(2147483904.0f, StrtofTrimmedChar("2147483904", 0));
1067+
CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483776", 0));
1068+
CHECK_EQ(2147483648.0f, StrtofTrimmedChar("214748377599999", -5));
1069+
CHECK_EQ(2147483904.0f, StrtofTrimmedChar("214748377600001", -5));
1070+
}
8791071

8801072
static int CompareBignumToDiyFp(const Bignum& bignum_digits,
8811073
int bignum_exponent,

0 commit comments

Comments
 (0)