Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: src/strtod.cc

Issue 3851003: Fix double-rounding in strtod. (Closed)
Patch Set: Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/cctest/test-strtod.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 78 // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
79 10000000000000000000000.0 79 10000000000000000000000.0
80 }; 80 };
81 81
82 static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); 82 static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
83 83
84 84
85 extern "C" double gay_strtod(const char* s00, const char** se); 85 extern "C" double gay_strtod(const char* s00, const char** se);
86 86
87 static double old_strtod(Vector<const char> buffer, int exponent) { 87 static double old_strtod(Vector<const char> buffer, int exponent) {
88 // gay_strtod is broken on Linux,x86. For numbers with few decimal digits
89 // the computation is done using floating-point operations which (on Linux)
90 // are prone to double-rounding errors.
91 // By adding several zeroes to the buffer gay_strtod falls back to a slower
92 // (but correct) algorithm.
93 const int kInsertedZeroesCount = 20;
88 char gay_buffer[1024]; 94 char gay_buffer[1024];
89 Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer)); 95 Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer));
90 int pos = 0; 96 int pos = 0;
91 for (int i = 0; i < buffer.length(); ++i) { 97 for (int i = 0; i < buffer.length(); ++i) {
92 gay_buffer_vector[pos++] = buffer[i]; 98 gay_buffer_vector[pos++] = buffer[i];
93 } 99 }
100 for (int i = 0; i < kInsertedZeroesCount; ++i) {
101 gay_buffer_vector[pos++] = '0';
102 }
103 exponent -= kInsertedZeroesCount;
94 gay_buffer_vector[pos++] = 'e'; 104 gay_buffer_vector[pos++] = 'e';
95 if (exponent < 0) { 105 if (exponent < 0) {
96 gay_buffer_vector[pos++] = '-'; 106 gay_buffer_vector[pos++] = '-';
97 exponent = -exponent; 107 exponent = -exponent;
98 } 108 }
99 const int kNumberOfExponentDigits = 5; 109 const int kNumberOfExponentDigits = 5;
100 for (int i = kNumberOfExponentDigits - 1; i >= 0; i--) { 110 for (int i = kNumberOfExponentDigits - 1; i >= 0; i--) {
101 gay_buffer_vector[pos + i] = exponent % 10 + '0'; 111 gay_buffer_vector[pos + i] = exponent % 10 + '0';
102 exponent /= 10; 112 exponent /= 10;
103 } 113 }
(...skipping 28 matching lines...) Expand all
132 uint64_t result = 0; 142 uint64_t result = 0;
133 for (int i = 0; i < buffer.length(); ++i) { 143 for (int i = 0; i < buffer.length(); ++i) {
134 int digit = buffer[i] - '0'; 144 int digit = buffer[i] - '0';
135 ASSERT(0 <= digit && digit <= 9); 145 ASSERT(0 <= digit && digit <= 9);
136 result = 10 * result + digit; 146 result = 10 * result + digit;
137 } 147 }
138 return result; 148 return result;
139 } 149 }
140 150
141 151
142 double Strtod(Vector<const char> buffer, int exponent) { 152 static bool DoubleStrtod(Vector<const char> trimmed,
143 Vector<const char> left_trimmed = TrimLeadingZeros(buffer); 153 int exponent,
144 Vector<const char> trimmed = TrimTrailingZeros(left_trimmed); 154 double* result) {
145 exponent += left_trimmed.length() - trimmed.length(); 155 #if defined(V8_TARGET_ARCH_IA32) && !defined(WIN32)
146 if (trimmed.length() == 0) return 0.0; 156 // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
147 if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY; 157 // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
148 if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0; 158 // result is not accurate.
159 // We know that Windows32 uses 64 bits and is therefore accurate.
160 return false;
161 #endif
149 if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { 162 if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
150 // The trimmed input fits into a double. 163 // The trimmed input fits into a double.
151 // If the 10^exponent (resp. 10^-exponent) fits into a double too then we 164 // If the 10^exponent (resp. 10^-exponent) fits into a double too then we
152 // can compute the result-double simply by multiplying (resp. dividing) the 165 // can compute the result-double simply by multiplying (resp. dividing) the
153 // two numbers. 166 // two numbers.
154 // This is possible because IEEE guarantees that floating-point operations 167 // This is possible because IEEE guarantees that floating-point operations
155 // return the best possible approximation. 168 // return the best possible approximation.
156 if (exponent < 0 && -exponent < kExactPowersOfTenSize) { 169 if (exponent < 0 && -exponent < kExactPowersOfTenSize) {
157 // 10^-exponent fits into a double. 170 // 10^-exponent fits into a double.
158 double buffer_d = static_cast<double>(ReadUint64(trimmed)); 171 *result = static_cast<double>(ReadUint64(trimmed));
159 return buffer_d / exact_powers_of_ten[-exponent]; 172 *result /= exact_powers_of_ten[-exponent];
173 return true;
160 } 174 }
161 if (0 <= exponent && exponent < kExactPowersOfTenSize) { 175 if (0 <= exponent && exponent < kExactPowersOfTenSize) {
162 // 10^exponent fits into a double. 176 // 10^exponent fits into a double.
163 double buffer_d = static_cast<double>(ReadUint64(trimmed)); 177 *result = static_cast<double>(ReadUint64(trimmed));
164 return buffer_d * exact_powers_of_ten[exponent]; 178 *result *= exact_powers_of_ten[exponent];
179 return true;
165 } 180 }
166 int remaining_digits = 181 int remaining_digits =
167 kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); 182 kMaxExactDoubleIntegerDecimalDigits - trimmed.length();
168 if ((0 <= exponent) && 183 if ((0 <= exponent) &&
169 (exponent - remaining_digits < kExactPowersOfTenSize)) { 184 (exponent - remaining_digits < kExactPowersOfTenSize)) {
170 // The trimmed string was short and we can multiply it with 185 // The trimmed string was short and we can multiply it with
171 // 10^remaining_digits. As a result the remaining exponent now fits 186 // 10^remaining_digits. As a result the remaining exponent now fits
172 // into a double too. 187 // into a double too.
173 double buffer_d = static_cast<double>(ReadUint64(trimmed)); 188 *result = static_cast<double>(ReadUint64(trimmed));
174 buffer_d *= exact_powers_of_ten[remaining_digits]; 189 *result *= exact_powers_of_ten[remaining_digits];
175 return buffer_d * exact_powers_of_ten[exponent - remaining_digits]; 190 *result *= exact_powers_of_ten[exponent - remaining_digits];
191 return true;
176 } 192 }
177 } 193 }
194 return false;
195 }
196
197
198 double Strtod(Vector<const char> buffer, int exponent) {
199 Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
200 Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
201 exponent += left_trimmed.length() - trimmed.length();
202 if (trimmed.length() == 0) return 0.0;
203 if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY;
204 if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0;
205 double result;
206 if (DoubleStrtod(trimmed, exponent, &result)) {
207 return result;
208 }
178 return old_strtod(trimmed, exponent); 209 return old_strtod(trimmed, exponent);
179 } 210 }
180 211
181 } } // namespace v8::internal 212 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | test/cctest/test-strtod.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698