| Index: runtime/third_party/double-conversion/src/strtod.cc
|
| ===================================================================
|
| --- runtime/third_party/double-conversion/src/strtod.cc (revision 33139)
|
| +++ runtime/third_party/double-conversion/src/strtod.cc (working copy)
|
| @@ -31,7 +31,7 @@
|
| #include "strtod.h"
|
| #include "bignum.h"
|
| #include "cached-powers.h"
|
| -#include "double.h"
|
| +#include "ieee.h"
|
|
|
| namespace double_conversion {
|
|
|
| @@ -108,7 +108,7 @@
|
| }
|
|
|
|
|
| -static void TrimToMaxSignificantDigits(Vector<const char> buffer,
|
| +static void CutToMaxSignificantDigits(Vector<const char> buffer,
|
| int exponent,
|
| char* significant_buffer,
|
| int* significant_exponent) {
|
| @@ -125,6 +125,31 @@
|
| exponent + (buffer.length() - kMaxSignificantDecimalDigits);
|
| }
|
|
|
| +
|
| +// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits.
|
| +// If possible the input-buffer is reused, but if the buffer needs to be
|
| +// modified (due to cutting), then the input needs to be copied into the
|
| +// buffer_copy_space.
|
| +static void TrimAndCut(Vector<const char> buffer, int exponent,
|
| + char* buffer_copy_space, int space_size,
|
| + Vector<const char>* trimmed, int* updated_exponent) {
|
| + Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
|
| + Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
|
| + exponent += left_trimmed.length() - right_trimmed.length();
|
| + if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
|
| + (void) space_size; // Mark variable as used.
|
| + ASSERT(space_size >= kMaxSignificantDecimalDigits);
|
| + CutToMaxSignificantDigits(right_trimmed, exponent,
|
| + buffer_copy_space, updated_exponent);
|
| + *trimmed = Vector<const char>(buffer_copy_space,
|
| + kMaxSignificantDecimalDigits);
|
| + } else {
|
| + *trimmed = right_trimmed;
|
| + *updated_exponent = exponent;
|
| + }
|
| +}
|
| +
|
| +
|
| // Reads digits from the buffer and converts them to a uint64.
|
| // Reads in as many digits as fit into a uint64.
|
| // When the string starts with "1844674407370955161" no further digit is read.
|
| @@ -239,7 +264,6 @@
|
| case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);
|
| default:
|
| UNREACHABLE();
|
| - return DiyFp(0, 0);
|
| }
|
| }
|
|
|
| @@ -357,22 +381,17 @@
|
| }
|
|
|
|
|
| -// Returns the correct double for the buffer*10^exponent.
|
| -// The variable guess should be a close guess that is either the correct double
|
| -// or its lower neighbor (the nearest double less than the correct one).
|
| +// Returns
|
| +// - -1 if buffer*10^exponent < diy_fp.
|
| +// - 0 if buffer*10^exponent == diy_fp.
|
| +// - +1 if buffer*10^exponent > diy_fp.
|
| // Preconditions:
|
| // buffer.length() + exponent <= kMaxDecimalPower + 1
|
| // buffer.length() + exponent > kMinDecimalPower
|
| // buffer.length() <= kMaxDecimalSignificantDigits
|
| -static double BignumStrtod(Vector<const char> buffer,
|
| - int exponent,
|
| - double guess) {
|
| - if (guess == Double::Infinity()) {
|
| - return guess;
|
| - }
|
| -
|
| - DiyFp upper_boundary = Double(guess).UpperBoundary();
|
| -
|
| +static int CompareBufferWithDiyFp(Vector<const char> buffer,
|
| + int exponent,
|
| + DiyFp diy_fp) {
|
| ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
|
| ASSERT(buffer.length() + exponent > kMinDecimalPower);
|
| ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
|
| @@ -381,21 +400,65 @@
|
| // consume at most one bigit (< 64 bits).
|
| // ln(10) == 3.3219...
|
| ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
|
| - Bignum input;
|
| - Bignum boundary;
|
| - input.AssignDecimalString(buffer);
|
| - boundary.AssignUInt64(upper_boundary.f());
|
| + Bignum buffer_bignum;
|
| + Bignum diy_fp_bignum;
|
| + buffer_bignum.AssignDecimalString(buffer);
|
| + diy_fp_bignum.AssignUInt64(diy_fp.f());
|
| if (exponent >= 0) {
|
| - input.MultiplyByPowerOfTen(exponent);
|
| + buffer_bignum.MultiplyByPowerOfTen(exponent);
|
| } else {
|
| - boundary.MultiplyByPowerOfTen(-exponent);
|
| + diy_fp_bignum.MultiplyByPowerOfTen(-exponent);
|
| }
|
| - if (upper_boundary.e() > 0) {
|
| - boundary.ShiftLeft(upper_boundary.e());
|
| + if (diy_fp.e() > 0) {
|
| + diy_fp_bignum.ShiftLeft(diy_fp.e());
|
| } else {
|
| - input.ShiftLeft(-upper_boundary.e());
|
| + buffer_bignum.ShiftLeft(-diy_fp.e());
|
| }
|
| - int comparison = Bignum::Compare(input, boundary);
|
| + return Bignum::Compare(buffer_bignum, diy_fp_bignum);
|
| +}
|
| +
|
| +
|
| +// Returns true if the guess is the correct double.
|
| +// Returns false, when guess is either correct or the next-lower double.
|
| +static bool ComputeGuess(Vector<const char> trimmed, int exponent,
|
| + double* guess) {
|
| + if (trimmed.length() == 0) {
|
| + *guess = 0.0;
|
| + return true;
|
| + }
|
| + if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
|
| + *guess = Double::Infinity();
|
| + return true;
|
| + }
|
| + if (exponent + trimmed.length() <= kMinDecimalPower) {
|
| + *guess = 0.0;
|
| + return true;
|
| + }
|
| +
|
| + if (DoubleStrtod(trimmed, exponent, guess) ||
|
| + DiyFpStrtod(trimmed, exponent, guess)) {
|
| + return true;
|
| + }
|
| + if (*guess == Double::Infinity()) {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +double Strtod(Vector<const char> buffer, int exponent) {
|
| + char copy_buffer[kMaxSignificantDecimalDigits];
|
| + Vector<const char> trimmed;
|
| + int updated_exponent;
|
| + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
|
| + &trimmed, &updated_exponent);
|
| + exponent = updated_exponent;
|
| +
|
| + double guess;
|
| + bool is_correct = ComputeGuess(trimmed, exponent, &guess);
|
| + if (is_correct) return guess;
|
| +
|
| + DiyFp upper_boundary = Double(guess).UpperBoundary();
|
| + int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
|
| if (comparison < 0) {
|
| return guess;
|
| } else if (comparison > 0) {
|
| @@ -408,34 +471,85 @@
|
| }
|
| }
|
|
|
| +float Strtof(Vector<const char> buffer, int exponent) {
|
| + char copy_buffer[kMaxSignificantDecimalDigits];
|
| + Vector<const char> trimmed;
|
| + int updated_exponent;
|
| + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
|
| + &trimmed, &updated_exponent);
|
| + exponent = updated_exponent;
|
|
|
| -double Strtod(Vector<const char> buffer, int exponent) {
|
| - Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
|
| - Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
|
| - exponent += left_trimmed.length() - trimmed.length();
|
| - if (trimmed.length() == 0) return 0.0;
|
| - if (trimmed.length() > kMaxSignificantDecimalDigits) {
|
| - char significant_buffer[kMaxSignificantDecimalDigits];
|
| - int significant_exponent;
|
| - TrimToMaxSignificantDigits(trimmed, exponent,
|
| - significant_buffer, &significant_exponent);
|
| - return Strtod(Vector<const char>(significant_buffer,
|
| - kMaxSignificantDecimalDigits),
|
| - significant_exponent);
|
| + double double_guess;
|
| + bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
|
| +
|
| + float float_guess = static_cast<float>(double_guess);
|
| + if (float_guess == double_guess) {
|
| + // This shortcut triggers for integer values.
|
| + return float_guess;
|
| }
|
| - if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
|
| - return Double::Infinity();
|
| +
|
| + // We must catch double-rounding. Say the double has been rounded up, and is
|
| + // now a boundary of a float, and rounds up again. This is why we have to
|
| + // look at previous too.
|
| + // Example (in decimal numbers):
|
| + // input: 12349
|
| + // high-precision (4 digits): 1235
|
| + // low-precision (3 digits):
|
| + // when read from input: 123
|
| + // when rounded from high precision: 124.
|
| + // To do this we simply look at the neigbors of the correct result and see
|
| + // if they would round to the same float. If the guess is not correct we have
|
| + // to look at four values (since two different doubles could be the correct
|
| + // double).
|
| +
|
| + double double_next = Double(double_guess).NextDouble();
|
| + double double_previous = Double(double_guess).PreviousDouble();
|
| +
|
| + float f1 = static_cast<float>(double_previous);
|
| + float f2 = float_guess;
|
| + float f3 = static_cast<float>(double_next);
|
| + float f4;
|
| + if (is_correct) {
|
| + f4 = f3;
|
| + } else {
|
| + double double_next2 = Double(double_next).NextDouble();
|
| + f4 = static_cast<float>(double_next2);
|
| }
|
| - if (exponent + trimmed.length() <= kMinDecimalPower) {
|
| - return 0.0;
|
| + (void) f2; // Mark variable as used.
|
| + ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
|
| +
|
| + // If the guess doesn't lie near a single-precision boundary we can simply
|
| + // return its float-value.
|
| + if (f1 == f4) {
|
| + return float_guess;
|
| }
|
|
|
| - double guess;
|
| - if (DoubleStrtod(trimmed, exponent, &guess) ||
|
| - DiyFpStrtod(trimmed, exponent, &guess)) {
|
| + ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
|
| + (f1 == f2 && f2 != f3 && f3 == f4) ||
|
| + (f1 == f2 && f2 == f3 && f3 != f4));
|
| +
|
| + // guess and next are the two possible canditates (in the same way that
|
| + // double_guess was the lower candidate for a double-precision guess).
|
| + float guess = f1;
|
| + float next = f4;
|
| + DiyFp upper_boundary;
|
| + if (guess == 0.0f) {
|
| + float min_float = 1e-45f;
|
| + upper_boundary = Double(static_cast<double>(min_float) / 2).AsDiyFp();
|
| + } else {
|
| + upper_boundary = Single(guess).UpperBoundary();
|
| + }
|
| + int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
|
| + if (comparison < 0) {
|
| return guess;
|
| + } else if (comparison > 0) {
|
| + return next;
|
| + } else if ((Single(guess).Significand() & 1) == 0) {
|
| + // Round towards even.
|
| + return guess;
|
| + } else {
|
| + return next;
|
| }
|
| - return BignumStrtod(trimmed, exponent, guess);
|
| }
|
|
|
| } // namespace double_conversion
|
|
|