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

Side by Side Diff: runtime/third_party/double-conversion/src/strtod.cc

Issue 184153002: - Update runtime/third_party/double-conversion to version 1.1.5. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 9 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 | Annotate | Revision Log
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 13 matching lines...) Expand all
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include <stdarg.h> 28 #include <stdarg.h>
29 #include <limits.h> 29 #include <limits.h>
30 30
31 #include "strtod.h" 31 #include "strtod.h"
32 #include "bignum.h" 32 #include "bignum.h"
33 #include "cached-powers.h" 33 #include "cached-powers.h"
34 #include "double.h" 34 #include "ieee.h"
35 35
36 namespace double_conversion { 36 namespace double_conversion {
37 37
38 // 2^53 = 9007199254740992. 38 // 2^53 = 9007199254740992.
39 // Any integer with at most 15 decimal digits will hence fit into a double 39 // Any integer with at most 15 decimal digits will hence fit into a double
40 // (which has a 53bit significand) without loss of precision. 40 // (which has a 53bit significand) without loss of precision.
41 static const int kMaxExactDoubleIntegerDecimalDigits = 15; 41 static const int kMaxExactDoubleIntegerDecimalDigits = 15;
42 // 2^64 = 18446744073709551616 > 10^19 42 // 2^64 = 18446744073709551616 > 10^19
43 static const int kMaxUint64DecimalDigits = 19; 43 static const int kMaxUint64DecimalDigits = 19;
44 44
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) { 101 static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
102 for (int i = buffer.length() - 1; i >= 0; --i) { 102 for (int i = buffer.length() - 1; i >= 0; --i) {
103 if (buffer[i] != '0') { 103 if (buffer[i] != '0') {
104 return buffer.SubVector(0, i + 1); 104 return buffer.SubVector(0, i + 1);
105 } 105 }
106 } 106 }
107 return Vector<const char>(buffer.start(), 0); 107 return Vector<const char>(buffer.start(), 0);
108 } 108 }
109 109
110 110
111 static void TrimToMaxSignificantDigits(Vector<const char> buffer, 111 static void CutToMaxSignificantDigits(Vector<const char> buffer,
112 int exponent, 112 int exponent,
113 char* significant_buffer, 113 char* significant_buffer,
114 int* significant_exponent) { 114 int* significant_exponent) {
115 for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { 115 for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
116 significant_buffer[i] = buffer[i]; 116 significant_buffer[i] = buffer[i];
117 } 117 }
118 // The input buffer has been trimmed. Therefore the last digit must be 118 // The input buffer has been trimmed. Therefore the last digit must be
119 // different from '0'. 119 // different from '0'.
120 ASSERT(buffer[buffer.length() - 1] != '0'); 120 ASSERT(buffer[buffer.length() - 1] != '0');
121 // Set the last digit to be non-zero. This is sufficient to guarantee 121 // Set the last digit to be non-zero. This is sufficient to guarantee
122 // correct rounding. 122 // correct rounding.
123 significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; 123 significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
124 *significant_exponent = 124 *significant_exponent =
125 exponent + (buffer.length() - kMaxSignificantDecimalDigits); 125 exponent + (buffer.length() - kMaxSignificantDecimalDigits);
126 } 126 }
127 127
128
129 // Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits.
130 // If possible the input-buffer is reused, but if the buffer needs to be
131 // modified (due to cutting), then the input needs to be copied into the
132 // buffer_copy_space.
133 static void TrimAndCut(Vector<const char> buffer, int exponent,
134 char* buffer_copy_space, int space_size,
135 Vector<const char>* trimmed, int* updated_exponent) {
136 Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
137 Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
138 exponent += left_trimmed.length() - right_trimmed.length();
139 if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
140 (void) space_size; // Mark variable as used.
141 ASSERT(space_size >= kMaxSignificantDecimalDigits);
142 CutToMaxSignificantDigits(right_trimmed, exponent,
143 buffer_copy_space, updated_exponent);
144 *trimmed = Vector<const char>(buffer_copy_space,
145 kMaxSignificantDecimalDigits);
146 } else {
147 *trimmed = right_trimmed;
148 *updated_exponent = exponent;
149 }
150 }
151
152
128 // Reads digits from the buffer and converts them to a uint64. 153 // Reads digits from the buffer and converts them to a uint64.
129 // Reads in as many digits as fit into a uint64. 154 // Reads in as many digits as fit into a uint64.
130 // When the string starts with "1844674407370955161" no further digit is read. 155 // When the string starts with "1844674407370955161" no further digit is read.
131 // Since 2^64 = 18446744073709551616 it would still be possible read another 156 // Since 2^64 = 18446744073709551616 it would still be possible read another
132 // digit if it was less or equal than 6, but this would complicate the code. 157 // digit if it was less or equal than 6, but this would complicate the code.
133 static uint64_t ReadUint64(Vector<const char> buffer, 158 static uint64_t ReadUint64(Vector<const char> buffer,
134 int* number_of_read_digits) { 159 int* number_of_read_digits) {
135 uint64_t result = 0; 160 uint64_t result = 0;
136 int i = 0; 161 int i = 0;
137 while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { 162 while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 switch (exponent) { 257 switch (exponent) {
233 case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); 258 case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60);
234 case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); 259 case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57);
235 case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); 260 case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54);
236 case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); 261 case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50);
237 case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); 262 case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47);
238 case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); 263 case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44);
239 case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); 264 case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);
240 default: 265 default:
241 UNREACHABLE(); 266 UNREACHABLE();
242 return DiyFp(0, 0);
243 } 267 }
244 } 268 }
245 269
246 270
247 // If the function returns true then the result is the correct double. 271 // If the function returns true then the result is the correct double.
248 // Otherwise it is either the correct double or the double that is just below 272 // Otherwise it is either the correct double or the double that is just below
249 // the correct double. 273 // the correct double.
250 static bool DiyFpStrtod(Vector<const char> buffer, 274 static bool DiyFpStrtod(Vector<const char> buffer,
251 int exponent, 275 int exponent,
252 double* result) { 276 double* result) {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 // Too imprecise. The caller will have to fall back to a slower version. 374 // Too imprecise. The caller will have to fall back to a slower version.
351 // However the returned number is guaranteed to be either the correct 375 // However the returned number is guaranteed to be either the correct
352 // double, or the next-lower double. 376 // double, or the next-lower double.
353 return false; 377 return false;
354 } else { 378 } else {
355 return true; 379 return true;
356 } 380 }
357 } 381 }
358 382
359 383
360 // Returns the correct double for the buffer*10^exponent. 384 // Returns
361 // The variable guess should be a close guess that is either the correct double 385 // - -1 if buffer*10^exponent < diy_fp.
362 // or its lower neighbor (the nearest double less than the correct one). 386 // - 0 if buffer*10^exponent == diy_fp.
387 // - +1 if buffer*10^exponent > diy_fp.
363 // Preconditions: 388 // Preconditions:
364 // buffer.length() + exponent <= kMaxDecimalPower + 1 389 // buffer.length() + exponent <= kMaxDecimalPower + 1
365 // buffer.length() + exponent > kMinDecimalPower 390 // buffer.length() + exponent > kMinDecimalPower
366 // buffer.length() <= kMaxDecimalSignificantDigits 391 // buffer.length() <= kMaxDecimalSignificantDigits
367 static double BignumStrtod(Vector<const char> buffer, 392 static int CompareBufferWithDiyFp(Vector<const char> buffer,
368 int exponent, 393 int exponent,
369 double guess) { 394 DiyFp diy_fp) {
370 if (guess == Double::Infinity()) {
371 return guess;
372 }
373
374 DiyFp upper_boundary = Double(guess).UpperBoundary();
375
376 ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); 395 ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
377 ASSERT(buffer.length() + exponent > kMinDecimalPower); 396 ASSERT(buffer.length() + exponent > kMinDecimalPower);
378 ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); 397 ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
379 // Make sure that the Bignum will be able to hold all our numbers. 398 // Make sure that the Bignum will be able to hold all our numbers.
380 // Our Bignum implementation has a separate field for exponents. Shifts will 399 // Our Bignum implementation has a separate field for exponents. Shifts will
381 // consume at most one bigit (< 64 bits). 400 // consume at most one bigit (< 64 bits).
382 // ln(10) == 3.3219... 401 // ln(10) == 3.3219...
383 ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); 402 ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
384 Bignum input; 403 Bignum buffer_bignum;
385 Bignum boundary; 404 Bignum diy_fp_bignum;
386 input.AssignDecimalString(buffer); 405 buffer_bignum.AssignDecimalString(buffer);
387 boundary.AssignUInt64(upper_boundary.f()); 406 diy_fp_bignum.AssignUInt64(diy_fp.f());
388 if (exponent >= 0) { 407 if (exponent >= 0) {
389 input.MultiplyByPowerOfTen(exponent); 408 buffer_bignum.MultiplyByPowerOfTen(exponent);
390 } else { 409 } else {
391 boundary.MultiplyByPowerOfTen(-exponent); 410 diy_fp_bignum.MultiplyByPowerOfTen(-exponent);
392 } 411 }
393 if (upper_boundary.e() > 0) { 412 if (diy_fp.e() > 0) {
394 boundary.ShiftLeft(upper_boundary.e()); 413 diy_fp_bignum.ShiftLeft(diy_fp.e());
395 } else { 414 } else {
396 input.ShiftLeft(-upper_boundary.e()); 415 buffer_bignum.ShiftLeft(-diy_fp.e());
397 } 416 }
398 int comparison = Bignum::Compare(input, boundary); 417 return Bignum::Compare(buffer_bignum, diy_fp_bignum);
418 }
419
420
421 // Returns true if the guess is the correct double.
422 // Returns false, when guess is either correct or the next-lower double.
423 static bool ComputeGuess(Vector<const char> trimmed, int exponent,
424 double* guess) {
425 if (trimmed.length() == 0) {
426 *guess = 0.0;
427 return true;
428 }
429 if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
430 *guess = Double::Infinity();
431 return true;
432 }
433 if (exponent + trimmed.length() <= kMinDecimalPower) {
434 *guess = 0.0;
435 return true;
436 }
437
438 if (DoubleStrtod(trimmed, exponent, guess) ||
439 DiyFpStrtod(trimmed, exponent, guess)) {
440 return true;
441 }
442 if (*guess == Double::Infinity()) {
443 return true;
444 }
445 return false;
446 }
447
448 double Strtod(Vector<const char> buffer, int exponent) {
449 char copy_buffer[kMaxSignificantDecimalDigits];
450 Vector<const char> trimmed;
451 int updated_exponent;
452 TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
453 &trimmed, &updated_exponent);
454 exponent = updated_exponent;
455
456 double guess;
457 bool is_correct = ComputeGuess(trimmed, exponent, &guess);
458 if (is_correct) return guess;
459
460 DiyFp upper_boundary = Double(guess).UpperBoundary();
461 int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
399 if (comparison < 0) { 462 if (comparison < 0) {
400 return guess; 463 return guess;
401 } else if (comparison > 0) { 464 } else if (comparison > 0) {
402 return Double(guess).NextDouble(); 465 return Double(guess).NextDouble();
403 } else if ((Double(guess).Significand() & 1) == 0) { 466 } else if ((Double(guess).Significand() & 1) == 0) {
404 // Round towards even. 467 // Round towards even.
405 return guess; 468 return guess;
406 } else { 469 } else {
407 return Double(guess).NextDouble(); 470 return Double(guess).NextDouble();
408 } 471 }
409 } 472 }
410 473
474 float Strtof(Vector<const char> buffer, int exponent) {
475 char copy_buffer[kMaxSignificantDecimalDigits];
476 Vector<const char> trimmed;
477 int updated_exponent;
478 TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
479 &trimmed, &updated_exponent);
480 exponent = updated_exponent;
411 481
412 double Strtod(Vector<const char> buffer, int exponent) { 482 double double_guess;
413 Vector<const char> left_trimmed = TrimLeadingZeros(buffer); 483 bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
414 Vector<const char> trimmed = TrimTrailingZeros(left_trimmed); 484
415 exponent += left_trimmed.length() - trimmed.length(); 485 float float_guess = static_cast<float>(double_guess);
416 if (trimmed.length() == 0) return 0.0; 486 if (float_guess == double_guess) {
417 if (trimmed.length() > kMaxSignificantDecimalDigits) { 487 // This shortcut triggers for integer values.
418 char significant_buffer[kMaxSignificantDecimalDigits]; 488 return float_guess;
419 int significant_exponent;
420 TrimToMaxSignificantDigits(trimmed, exponent,
421 significant_buffer, &significant_exponent);
422 return Strtod(Vector<const char>(significant_buffer,
423 kMaxSignificantDecimalDigits),
424 significant_exponent);
425 }
426 if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
427 return Double::Infinity();
428 }
429 if (exponent + trimmed.length() <= kMinDecimalPower) {
430 return 0.0;
431 } 489 }
432 490
433 double guess; 491 // We must catch double-rounding. Say the double has been rounded up, and is
434 if (DoubleStrtod(trimmed, exponent, &guess) || 492 // now a boundary of a float, and rounds up again. This is why we have to
435 DiyFpStrtod(trimmed, exponent, &guess)) { 493 // look at previous too.
494 // Example (in decimal numbers):
495 // input: 12349
496 // high-precision (4 digits): 1235
497 // low-precision (3 digits):
498 // when read from input: 123
499 // when rounded from high precision: 124.
500 // To do this we simply look at the neigbors of the correct result and see
501 // if they would round to the same float. If the guess is not correct we have
502 // to look at four values (since two different doubles could be the correct
503 // double).
504
505 double double_next = Double(double_guess).NextDouble();
506 double double_previous = Double(double_guess).PreviousDouble();
507
508 float f1 = static_cast<float>(double_previous);
509 float f2 = float_guess;
510 float f3 = static_cast<float>(double_next);
511 float f4;
512 if (is_correct) {
513 f4 = f3;
514 } else {
515 double double_next2 = Double(double_next).NextDouble();
516 f4 = static_cast<float>(double_next2);
517 }
518 (void) f2; // Mark variable as used.
519 ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
520
521 // If the guess doesn't lie near a single-precision boundary we can simply
522 // return its float-value.
523 if (f1 == f4) {
524 return float_guess;
525 }
526
527 ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
528 (f1 == f2 && f2 != f3 && f3 == f4) ||
529 (f1 == f2 && f2 == f3 && f3 != f4));
530
531 // guess and next are the two possible canditates (in the same way that
532 // double_guess was the lower candidate for a double-precision guess).
533 float guess = f1;
534 float next = f4;
535 DiyFp upper_boundary;
536 if (guess == 0.0f) {
537 float min_float = 1e-45f;
538 upper_boundary = Double(static_cast<double>(min_float) / 2).AsDiyFp();
539 } else {
540 upper_boundary = Single(guess).UpperBoundary();
541 }
542 int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
543 if (comparison < 0) {
436 return guess; 544 return guess;
545 } else if (comparison > 0) {
546 return next;
547 } else if ((Single(guess).Significand() & 1) == 0) {
548 // Round towards even.
549 return guess;
550 } else {
551 return next;
437 } 552 }
438 return BignumStrtod(trimmed, exponent, guess);
439 } 553 }
440 554
441 } // namespace double_conversion 555 } // namespace double_conversion
OLDNEW
« no previous file with comments | « runtime/third_party/double-conversion/src/strtod.h ('k') | runtime/third_party/double-conversion/src/utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698