OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |