]> granicus.if.org Git - icu/commitdiff
ICU-21480 Update double-conversion release-69-rc
authorShane F. Carr <shane@unicode.org>
Wed, 17 Mar 2021 18:26:35 +0000 (13:26 -0500)
committerShane F. Carr <shane@unicode.org>
Thu, 18 Mar 2021 00:45:13 +0000 (19:45 -0500)
15 files changed:
icu4c/source/i18n/double-conversion-double-to-string.cpp
icu4c/source/i18n/double-conversion-double-to-string.h
icu4c/source/i18n/double-conversion-string-to-double.cpp
icu4c/source/i18n/double-conversion-strtod.cpp
icu4c/source/i18n/double-conversion-strtod.h
icu4c/source/i18n/double-conversion-utils.h
vendor/double-conversion/upstream/.gitignore
vendor/double-conversion/upstream/double-conversion/double-to-string.cc
vendor/double-conversion/upstream/double-conversion/double-to-string.h
vendor/double-conversion/upstream/double-conversion/string-to-double.cc
vendor/double-conversion/upstream/double-conversion/strtod.cc
vendor/double-conversion/upstream/double-conversion/strtod.h
vendor/double-conversion/upstream/double-conversion/utils.h
vendor/double-conversion/upstream/test/cctest/test-conversions.cc
vendor/double-conversion/upstream/test/cctest/test-strtod.cc

index 44c176f4f9c9585f52eabdd4d511e0c2db88ca9c..90ba4360600472338978620d208f364dba3653bc 100644 (file)
@@ -107,19 +107,19 @@ void DoubleToStringConverter::CreateExponentialRepresentation(
       result_builder->AddCharacter('+');
     }
   }
-  if (exponent == 0) {
-    result_builder->AddCharacter('0');
-    return;
-  }
   DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
   // Changing this constant requires updating the comment of DoubleToStringConverter constructor
   const int kMaxExponentLength = 5;
   char buffer[kMaxExponentLength + 1];
   buffer[kMaxExponentLength] = '\0';
   int first_char_pos = kMaxExponentLength;
-  while (exponent > 0) {
-    buffer[--first_char_pos] = '0' + (exponent % 10);
-    exponent /= 10;
+  if (exponent == 0) {
+    buffer[--first_char_pos] = '0';
+  } else {
+    while (exponent > 0) {
+      buffer[--first_char_pos] = '0' + (exponent % 10);
+      exponent /= 10;
+    }
   }
   // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
   // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
@@ -342,9 +342,21 @@ bool DoubleToStringConverter::ToPrecision(double value,
   int exponent = decimal_point - 1;
 
   int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
-  if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
+  bool as_exponential =
+      (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
       (decimal_point - precision + extra_zero >
-       max_trailing_padding_zeroes_in_precision_mode_)) {
+       max_trailing_padding_zeroes_in_precision_mode_);
+  if ((flags_ & NO_TRAILING_ZERO) != 0) {
+    // Truncate trailing zeros that occur after the decimal point (if exponential,
+    // that is everything after the first digit).
+    int stop = as_exponential ? 1 : std::max(1, decimal_point);
+    while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') {
+      --decimal_rep_length;
+    }
+    // Clamp precision to avoid the code below re-adding the zeros.
+    precision = std::min(precision, decimal_rep_length);
+  }
+  if (as_exponential) {
     // Fill buffer to contain 'precision' digits.
     // Usually the buffer is already at the correct length, but 'DoubleToAscii'
     // is allowed to return less characters.
index 27bd86784895f83479fb43cfeef805e0e34bddcf..73ff48f109ecd5c20888a379b28032e7f0e26bec 100644 (file)
@@ -48,12 +48,11 @@ namespace double_conversion {
 
 class DoubleToStringConverter {
  public:
-#if 0 // not needed for ICU
   // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
   // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
   // function returns false.
   static const int kMaxFixedDigitsBeforePoint = 60;
-  static const int kMaxFixedDigitsAfterPoint = 60;
+  static const int kMaxFixedDigitsAfterPoint = 100;
 
   // When calling ToExponential with a requested_digits
   // parameter > kMaxExponentialDigits then the function returns false.
@@ -65,12 +64,36 @@ class DoubleToStringConverter {
   static const int kMinPrecisionDigits = 1;
   static const int kMaxPrecisionDigits = 120;
 
+  // The maximal number of digits that are needed to emit a double in base 10.
+  // A higher precision can be achieved by using more digits, but the shortest
+  // accurate representation of any double will never use more digits than
+  // kBase10MaximalLength.
+  // Note that DoubleToAscii null-terminates its input. So the given buffer
+  // should be at least kBase10MaximalLength + 1 characters long.
+  static const int kBase10MaximalLength = 17;
+
+  // The maximal number of digits that are needed to emit a single in base 10.
+  // A higher precision can be achieved by using more digits, but the shortest
+  // accurate representation of any single will never use more digits than
+  // kBase10MaximalLengthSingle.
+  static const int kBase10MaximalLengthSingle = 9;
+
+  // The length of the longest string that 'ToShortest' can produce when the
+  // converter is instantiated with EcmaScript defaults (see
+  // 'EcmaScriptConverter')
+  // This value does not include the trailing '\0' character.
+  // This amount of characters is needed for negative values that hit the
+  // 'decimal_in_shortest_low' limit. For example: "-0.0000033333333333333333"
+  static const int kMaxCharsEcmaScriptShortest = 25;
+
+#if 0 // not needed for ICU
   enum Flags {
     NO_FLAGS = 0,
     EMIT_POSITIVE_EXPONENT_SIGN = 1,
     EMIT_TRAILING_DECIMAL_POINT = 2,
     EMIT_TRAILING_ZERO_AFTER_POINT = 4,
-    UNIQUE_ZERO = 8
+    UNIQUE_ZERO = 8,
+    NO_TRAILING_ZERO = 16
   };
 
   // Flags should be a bit-or combination of the possible Flags-enum.
@@ -82,9 +105,13 @@ class DoubleToStringConverter {
   //    Example: 2345.0 is converted to "2345.".
   //  - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
   //    emits a trailing '0'-character. This flag requires the
-  //    EXMIT_TRAILING_DECIMAL_POINT flag.
+  //    EMIT_TRAILING_DECIMAL_POINT flag.
   //    Example: 2345.0 is converted to "2345.0".
   //  - UNIQUE_ZERO: "-0.0" is converted to "0.0".
+  //  - NO_TRAILING_ZERO: Trailing zeros are removed from the fractional portion
+  //    of the result in precision mode. Matches printf's %g.
+  //    When EMIT_TRAILING_ZERO_AFTER_POINT is also given, one trailing zero is
+  //    preserved.
   //
   // Infinity symbol and nan_symbol provide the string representation for these
   // special values. If the string is NULL and the special value is encountered
@@ -152,6 +179,14 @@ class DoubleToStringConverter {
   }
 
   // Returns a converter following the EcmaScript specification.
+  //
+  // Flags: UNIQUE_ZERO and EMIT_POSITIVE_EXPONENT_SIGN.
+  // Special values: "Infinity" and "NaN".
+  // Lower case 'e' for exponential values.
+  // decimal_in_shortest_low: -6
+  // decimal_in_shortest_high: 21
+  // max_leading_padding_zeroes_in_precision_mode: 6
+  // max_trailing_padding_zeroes_in_precision_mode: 0
   static const DoubleToStringConverter& EcmaScriptConverter();
 
   // Computes the shortest string of digits that correctly represent the input
@@ -177,6 +212,21 @@ class DoubleToStringConverter {
   // Returns true if the conversion succeeds. The conversion always succeeds
   // except when the input value is special and no infinity_symbol or
   // nan_symbol has been given to the constructor.
+  //
+  // The length of the longest result is the maximum of the length of the
+  // following string representations (each with possible examples):
+  // - NaN and negative infinity: "NaN", "-Infinity", "-inf".
+  // - -10^(decimal_in_shortest_high - 1):
+  //      "-100000000000000000000", "-1000000000000000.0"
+  // - the longest string in range [0; -10^decimal_in_shortest_low]. Generally,
+  //   this string is 3 + kBase10MaximalLength - decimal_in_shortest_low.
+  //   (Sign, '0', decimal point, padding zeroes for decimal_in_shortest_low,
+  //   and the significant digits).
+  //      "-0.0000033333333333333333", "-0.0012345678901234567"
+  // - the longest exponential representation. (A negative number with
+  //   kBase10MaximalLength significant digits).
+  //      "-1.7976931348623157e+308", "-1.7976931348623157E308"
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToShortest(double value, StringBuilder* result_builder) const {
     return ToShortestIeeeNumber(value, result_builder, SHORTEST);
   }
@@ -217,9 +267,11 @@ class DoubleToStringConverter {
   //     been provided to the constructor,
   //   - 'value' > 10^kMaxFixedDigitsBeforePoint, or
   //   - 'requested_digits' > kMaxFixedDigitsAfterPoint.
-  // The last two conditions imply that the result will never contain more than
-  // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
+  // The last two conditions imply that the result for non-special values never
+  // contains more than
+  //  1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
   // (one additional character for the sign, and one for the decimal point).
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToFixed(double value,
                int requested_digits,
                StringBuilder* result_builder) const;
@@ -248,14 +300,17 @@ class DoubleToStringConverter {
   //   - the input value is special and no infinity_symbol or nan_symbol has
   //     been provided to the constructor,
   //   - 'requested_digits' > kMaxExponentialDigits.
-  // The last condition implies that the result will never contain more than
+  //
+  // The last condition implies that the result never contains more than
   // kMaxExponentialDigits + 8 characters (the sign, the digit before the
   // decimal point, the decimal point, the exponent character, the
   // exponent's sign, and at most 3 exponent digits).
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToExponential(double value,
                      int requested_digits,
                      StringBuilder* result_builder) const;
 
+
   // Computes 'precision' leading digits of the given 'value' and returns them
   // either in exponential or decimal format, depending on
   // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
@@ -287,9 +342,11 @@ class DoubleToStringConverter {
   //     been provided to the constructor,
   //   - precision < kMinPericisionDigits
   //   - precision > kMaxPrecisionDigits
-  // The last condition implies that the result will never contain more than
+  //
+  // The last condition implies that the result never contains more than
   // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
   // exponent character, the exponent's sign, and at most 3 exponent digits).
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToPrecision(double value,
                    int precision,
                    StringBuilder* result_builder) const;
@@ -310,14 +367,6 @@ class DoubleToStringConverter {
     PRECISION
   };
 
-  // The maximal number of digits that are needed to emit a double in base 10.
-  // A higher precision can be achieved by using more digits, but the shortest
-  // accurate representation of any double will never use more digits than
-  // kBase10MaximalLength.
-  // Note that DoubleToAscii null-terminates its input. So the given buffer
-  // should be at least kBase10MaximalLength + 1 characters long.
-  static const int kBase10MaximalLength = 17;
-
   // Converts the given double 'v' to digit characters. 'v' must not be NaN,
   // +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
   // applies to 'v' after it has been casted to a single-precision float. That
index 548cad1f3022416e29d58102701811e1df57df47..3275b9e552f66b0eb729595df73eeec9628f8099 100644 (file)
 // ICU PATCH: Wrap in ICU namespace
 U_NAMESPACE_BEGIN
 
+#ifdef _MSC_VER
+#  if _MSC_VER >= 1900
+// Fix MSVC >= 2015 (_MSC_VER == 1900) warning
+// C4244: 'argument': conversion from 'const uc16' to 'char', possible loss of data
+// against Advance and friends, when instantiated with **it as char, not uc16.
+ __pragma(warning(disable: 4244))
+#  endif
+#  if _MSC_VER <= 1700 // VS2012, see IsDecimalDigitForRadix warning fix, below
+#    define VS2012_RADIXWARN
+#  endif
+#endif
+
 namespace double_conversion {
 
 namespace {
@@ -170,9 +182,9 @@ static double SignedZero(bool sign) {
 //
 // The function is small and could be inlined, but VS2012 emitted a warning
 // because it constant-propagated the radix and concluded that the last
-// condition was always true. By moving it into a separate function the
-// compiler wouldn't warn anymore.
-#ifdef _MSC_VER
+// condition was always true. Moving it into a separate function and
+// suppressing optimisation keeps the compiler from warning.
+#ifdef VS2012_RADIXWARN
 #pragma optimize("",off)
 static bool IsDecimalDigitForRadix(int c, int radix) {
   return '0' <= c && c <= '9' && (c - '0') < radix;
@@ -738,11 +750,17 @@ double StringToDoubleConverter::StringToIeee(
   DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
   buffer[buffer_pos] = '\0';
 
+  // Code above ensures there are no leading zeros and the buffer has fewer than
+  // kMaxSignificantDecimalDigits characters. Trim trailing zeros.
+  Vector<const char> chars(buffer, buffer_pos);
+  chars = TrimTrailingZeros(chars);
+  exponent += buffer_pos - chars.length();
+
   double converted;
   if (read_as_double) {
-    converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+    converted = StrtodTrimmed(chars, exponent);
   } else {
-    converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
+    converted = StrtofTrimmed(chars, exponent);
   }
   *processed_characters_count = static_cast<int>(current - input);
   return sign? -converted: converted;
index ee6377782bb82fba972d811c42a5d554aa0b2b96..9eeaa2e40fc73c0390f81e5471a144a52274ba77 100644 (file)
@@ -115,17 +115,6 @@ static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
   return Vector<const char>(buffer.start(), 0);
 }
 
-
-static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
-  for (int i = buffer.length() - 1; i >= 0; --i) {
-    if (buffer[i] != '0') {
-      return buffer.SubVector(0, i + 1);
-    }
-  }
-  return Vector<const char>(buffer.start(), 0);
-}
-
-
 static void CutToMaxSignificantDigits(Vector<const char> buffer,
                                        int exponent,
                                        char* significant_buffer,
@@ -216,12 +205,14 @@ static bool DoubleStrtod(Vector<const char> trimmed,
                          int exponent,
                          double* result) {
 #if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+  // Avoid "unused parameter" warnings
+  (void) trimmed;
+  (void) exponent;
+  (void) result;
   // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
   // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
   // result is not accurate.
   // We know that Windows32 uses 64 bits and is therefore accurate.
-  // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
-  // the same problem.
   return false;
 #else
   if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
@@ -473,6 +464,11 @@ static bool IsNonZeroDigit(const char d) {
   return ('1' <= d) && (d <= '9');
 }
 
+#ifdef __has_cpp_attribute
+#if __has_cpp_attribute(maybe_unused)
+[[maybe_unused]]
+#endif
+#endif
 static bool AssertTrimmedDigits(const Vector<const char>& buffer) {
   for(int i = 0; i < buffer.length(); ++i) {
     if(!IsDigit(buffer[i])) {
@@ -545,6 +541,12 @@ float Strtof(Vector<const char> buffer, int exponent) {
   TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
              &trimmed, &updated_exponent);
   exponent = updated_exponent;
+  return StrtofTrimmed(trimmed, exponent);
+}
+
+float StrtofTrimmed(Vector<const char> trimmed, int exponent) {
+  DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
+  DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
 
   double double_guess;
   bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
index 50ef746401a90840b1012d87ffba87bfcc42680f..abfe00a333102ce0006819b2531552068c991404 100644 (file)
@@ -54,11 +54,25 @@ double Strtod(Vector<const char> buffer, int exponent);
 // contain a dot or a sign. It must not start with '0', and must not be empty.
 float Strtof(Vector<const char> buffer, int exponent);
 
-// For special use cases, the heart of the Strtod() function is also available
-// separately, it assumes that 'trimmed' is as produced by TrimAndCut(), i.e.
-// no leading or trailing zeros, also no lone zero, and not 'too many' digits.
+// Same as Strtod, but assumes that 'trimmed' is already trimmed, as if run
+// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
+// zeros, must not be a lone zero, and must not have 'too many' digits.
 double StrtodTrimmed(Vector<const char> trimmed, int exponent);
 
+// Same as Strtof, but assumes that 'trimmed' is already trimmed, as if run
+// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
+// zeros, must not be a lone zero, and must not have 'too many' digits.
+float StrtofTrimmed(Vector<const char> trimmed, int exponent);
+
+inline Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
+  for (int i = buffer.length() - 1; i >= 0; --i) {
+    if (buffer[i] != '0') {
+      return buffer.SubVector(0, i + 1);
+    }
+  }
+  return Vector<const char>(buffer.start(), 0);
+}
+
 }  // namespace double_conversion
 
 // ICU PATCH: Close ICU namespace
index 8c6a0e16e005fe2a80fc08d28dd7061ea2fcdbfa..c937463647135becaff0e2f9876f5ed4b19122dc 100644 (file)
@@ -118,7 +118,7 @@ int main(int argc, char** argv) {
     defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
     defined(__hppa__) || defined(__ia64__) || \
     defined(__mips__) || \
-    defined(__nios2__) || \
+    defined(__nios2__) || defined(__ghs) || \
     defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
     defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
     defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
index 38fa1a7e95970538e01b0b6364eb1653f42966f5..e402d0799e515bd61770eef1aef2a50f27060a39 100644 (file)
@@ -28,4 +28,4 @@ _deps
 *.kdev4
 DartConfiguration.tcl
 bazel-*
-
+.cache
index 4562f99f49a06971dea1c3674ae1d68c723cbaf2..9255bce1713e9a85cb1a9abff8d422623ada15af 100644 (file)
@@ -92,19 +92,19 @@ void DoubleToStringConverter::CreateExponentialRepresentation(
       result_builder->AddCharacter('+');
     }
   }
-  if (exponent == 0) {
-    result_builder->AddCharacter('0');
-    return;
-  }
   DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
   // Changing this constant requires updating the comment of DoubleToStringConverter constructor
   const int kMaxExponentLength = 5;
   char buffer[kMaxExponentLength + 1];
   buffer[kMaxExponentLength] = '\0';
   int first_char_pos = kMaxExponentLength;
-  while (exponent > 0) {
-    buffer[--first_char_pos] = '0' + (exponent % 10);
-    exponent /= 10;
+  if (exponent == 0) {
+    buffer[--first_char_pos] = '0';
+  } else {
+    while (exponent > 0) {
+      buffer[--first_char_pos] = '0' + (exponent % 10);
+      exponent /= 10;
+    }
   }
   // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
   // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
@@ -327,9 +327,21 @@ bool DoubleToStringConverter::ToPrecision(double value,
   int exponent = decimal_point - 1;
 
   int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
-  if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
+  bool as_exponential =
+      (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
       (decimal_point - precision + extra_zero >
-       max_trailing_padding_zeroes_in_precision_mode_)) {
+       max_trailing_padding_zeroes_in_precision_mode_);
+  if ((flags_ & NO_TRAILING_ZERO) != 0) {
+    // Truncate trailing zeros that occur after the decimal point (if exponential,
+    // that is everything after the first digit).
+    int stop = as_exponential ? 1 : std::max(1, decimal_point);
+    while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') {
+      --decimal_rep_length;
+    }
+    // Clamp precision to avoid the code below re-adding the zeros.
+    precision = std::min(precision, decimal_rep_length);
+  }
+  if (as_exponential) {
     // Fill buffer to contain 'precision' digits.
     // Usually the buffer is already at the correct length, but 'DoubleToAscii'
     // is allowed to return less characters.
index a44fa3c7e94a744c2779d6289fc9418302e49cef..876a047f226bd12cbea85785d5b50cf4a42ff9a9 100644 (file)
@@ -38,7 +38,7 @@ class DoubleToStringConverter {
   // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
   // function returns false.
   static const int kMaxFixedDigitsBeforePoint = 60;
-  static const int kMaxFixedDigitsAfterPoint = 60;
+  static const int kMaxFixedDigitsAfterPoint = 100;
 
   // When calling ToExponential with a requested_digits
   // parameter > kMaxExponentialDigits then the function returns false.
@@ -50,12 +50,35 @@ class DoubleToStringConverter {
   static const int kMinPrecisionDigits = 1;
   static const int kMaxPrecisionDigits = 120;
 
+  // The maximal number of digits that are needed to emit a double in base 10.
+  // A higher precision can be achieved by using more digits, but the shortest
+  // accurate representation of any double will never use more digits than
+  // kBase10MaximalLength.
+  // Note that DoubleToAscii null-terminates its input. So the given buffer
+  // should be at least kBase10MaximalLength + 1 characters long.
+  static const int kBase10MaximalLength = 17;
+
+  // The maximal number of digits that are needed to emit a single in base 10.
+  // A higher precision can be achieved by using more digits, but the shortest
+  // accurate representation of any single will never use more digits than
+  // kBase10MaximalLengthSingle.
+  static const int kBase10MaximalLengthSingle = 9;
+
+  // The length of the longest string that 'ToShortest' can produce when the
+  // converter is instantiated with EcmaScript defaults (see
+  // 'EcmaScriptConverter')
+  // This value does not include the trailing '\0' character.
+  // This amount of characters is needed for negative values that hit the
+  // 'decimal_in_shortest_low' limit. For example: "-0.0000033333333333333333"
+  static const int kMaxCharsEcmaScriptShortest = 25;
+
   enum Flags {
     NO_FLAGS = 0,
     EMIT_POSITIVE_EXPONENT_SIGN = 1,
     EMIT_TRAILING_DECIMAL_POINT = 2,
     EMIT_TRAILING_ZERO_AFTER_POINT = 4,
-    UNIQUE_ZERO = 8
+    UNIQUE_ZERO = 8,
+    NO_TRAILING_ZERO = 16
   };
 
   // Flags should be a bit-or combination of the possible Flags-enum.
@@ -67,9 +90,13 @@ class DoubleToStringConverter {
   //    Example: 2345.0 is converted to "2345.".
   //  - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
   //    emits a trailing '0'-character. This flag requires the
-  //    EXMIT_TRAILING_DECIMAL_POINT flag.
+  //    EMIT_TRAILING_DECIMAL_POINT flag.
   //    Example: 2345.0 is converted to "2345.0".
   //  - UNIQUE_ZERO: "-0.0" is converted to "0.0".
+  //  - NO_TRAILING_ZERO: Trailing zeros are removed from the fractional portion
+  //    of the result in precision mode. Matches printf's %g.
+  //    When EMIT_TRAILING_ZERO_AFTER_POINT is also given, one trailing zero is
+  //    preserved.
   //
   // Infinity symbol and nan_symbol provide the string representation for these
   // special values. If the string is NULL and the special value is encountered
@@ -137,6 +164,14 @@ class DoubleToStringConverter {
   }
 
   // Returns a converter following the EcmaScript specification.
+  //
+  // Flags: UNIQUE_ZERO and EMIT_POSITIVE_EXPONENT_SIGN.
+  // Special values: "Infinity" and "NaN".
+  // Lower case 'e' for exponential values.
+  // decimal_in_shortest_low: -6
+  // decimal_in_shortest_high: 21
+  // max_leading_padding_zeroes_in_precision_mode: 6
+  // max_trailing_padding_zeroes_in_precision_mode: 0
   static const DoubleToStringConverter& EcmaScriptConverter();
 
   // Computes the shortest string of digits that correctly represent the input
@@ -162,6 +197,21 @@ class DoubleToStringConverter {
   // Returns true if the conversion succeeds. The conversion always succeeds
   // except when the input value is special and no infinity_symbol or
   // nan_symbol has been given to the constructor.
+  //
+  // The length of the longest result is the maximum of the length of the
+  // following string representations (each with possible examples):
+  // - NaN and negative infinity: "NaN", "-Infinity", "-inf".
+  // - -10^(decimal_in_shortest_high - 1):
+  //      "-100000000000000000000", "-1000000000000000.0"
+  // - the longest string in range [0; -10^decimal_in_shortest_low]. Generally,
+  //   this string is 3 + kBase10MaximalLength - decimal_in_shortest_low.
+  //   (Sign, '0', decimal point, padding zeroes for decimal_in_shortest_low,
+  //   and the significant digits).
+  //      "-0.0000033333333333333333", "-0.0012345678901234567"
+  // - the longest exponential representation. (A negative number with
+  //   kBase10MaximalLength significant digits).
+  //      "-1.7976931348623157e+308", "-1.7976931348623157E308"
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToShortest(double value, StringBuilder* result_builder) const {
     return ToShortestIeeeNumber(value, result_builder, SHORTEST);
   }
@@ -202,9 +252,11 @@ class DoubleToStringConverter {
   //     been provided to the constructor,
   //   - 'value' > 10^kMaxFixedDigitsBeforePoint, or
   //   - 'requested_digits' > kMaxFixedDigitsAfterPoint.
-  // The last two conditions imply that the result will never contain more than
-  // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
+  // The last two conditions imply that the result for non-special values never
+  // contains more than
+  //  1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
   // (one additional character for the sign, and one for the decimal point).
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToFixed(double value,
                int requested_digits,
                StringBuilder* result_builder) const;
@@ -233,14 +285,17 @@ class DoubleToStringConverter {
   //   - the input value is special and no infinity_symbol or nan_symbol has
   //     been provided to the constructor,
   //   - 'requested_digits' > kMaxExponentialDigits.
-  // The last condition implies that the result will never contain more than
+  //
+  // The last condition implies that the result never contains more than
   // kMaxExponentialDigits + 8 characters (the sign, the digit before the
   // decimal point, the decimal point, the exponent character, the
   // exponent's sign, and at most 3 exponent digits).
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToExponential(double value,
                      int requested_digits,
                      StringBuilder* result_builder) const;
 
+
   // Computes 'precision' leading digits of the given 'value' and returns them
   // either in exponential or decimal format, depending on
   // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
@@ -272,9 +327,11 @@ class DoubleToStringConverter {
   //     been provided to the constructor,
   //   - precision < kMinPericisionDigits
   //   - precision > kMaxPrecisionDigits
-  // The last condition implies that the result will never contain more than
+  //
+  // The last condition implies that the result never contains more than
   // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
   // exponent character, the exponent's sign, and at most 3 exponent digits).
+  // In addition, the buffer must be able to hold the trailing '\0' character.
   bool ToPrecision(double value,
                    int precision,
                    StringBuilder* result_builder) const;
@@ -294,14 +351,6 @@ class DoubleToStringConverter {
     PRECISION
   };
 
-  // The maximal number of digits that are needed to emit a double in base 10.
-  // A higher precision can be achieved by using more digits, but the shortest
-  // accurate representation of any double will never use more digits than
-  // kBase10MaximalLength.
-  // Note that DoubleToAscii null-terminates its input. So the given buffer
-  // should be at least kBase10MaximalLength + 1 characters long.
-  static const int kBase10MaximalLength = 17;
-
   // Converts the given double 'v' to digit characters. 'v' must not be NaN,
   // +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
   // applies to 'v' after it has been casted to a single-precision float. That
index 12b88f9b8014320a4c14da8a60ed810034bd3a95..85c3a082eb67c706dbb0c8cadd03a687a6e4113f 100644 (file)
 #include "strtod.h"
 #include "utils.h"
 
+#ifdef _MSC_VER
+#  if _MSC_VER >= 1900
+// Fix MSVC >= 2015 (_MSC_VER == 1900) warning
+// C4244: 'argument': conversion from 'const uc16' to 'char', possible loss of data
+// against Advance and friends, when instantiated with **it as char, not uc16.
+ __pragma(warning(disable: 4244))
+#  endif
+#  if _MSC_VER <= 1700 // VS2012, see IsDecimalDigitForRadix warning fix, below
+#    define VS2012_RADIXWARN
+#  endif
+#endif
+
 namespace double_conversion {
 
 namespace {
@@ -149,9 +161,9 @@ static double SignedZero(bool sign) {
 //
 // The function is small and could be inlined, but VS2012 emitted a warning
 // because it constant-propagated the radix and concluded that the last
-// condition was always true. By moving it into a separate function the
-// compiler wouldn't warn anymore.
-#ifdef _MSC_VER
+// condition was always true. Moving it into a separate function and
+// suppressing optimisation keeps the compiler from warning.
+#ifdef VS2012_RADIXWARN
 #pragma optimize("",off)
 static bool IsDecimalDigitForRadix(int c, int radix) {
   return '0' <= c && c <= '9' && (c - '0') < radix;
@@ -717,11 +729,17 @@ double StringToDoubleConverter::StringToIeee(
   DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
   buffer[buffer_pos] = '\0';
 
+  // Code above ensures there are no leading zeros and the buffer has fewer than
+  // kMaxSignificantDecimalDigits characters. Trim trailing zeros.
+  Vector<const char> chars(buffer, buffer_pos);
+  chars = TrimTrailingZeros(chars);
+  exponent += buffer_pos - chars.length();
+
   double converted;
   if (read_as_double) {
-    converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+    converted = StrtodTrimmed(chars, exponent);
   } else {
-    converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
+    converted = StrtofTrimmed(chars, exponent);
   }
   *processed_characters_count = static_cast<int>(current - input);
   return sign? -converted: converted;
index 3da7a42a7715659881b9c57a85df1a45be4c423a..0cc74951d9e0d54e5d897f951f877ec2ece473c3 100644 (file)
@@ -101,17 +101,6 @@ static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
   return Vector<const char>(buffer.start(), 0);
 }
 
-
-static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
-  for (int i = buffer.length() - 1; i >= 0; --i) {
-    if (buffer[i] != '0') {
-      return buffer.SubVector(0, i + 1);
-    }
-  }
-  return Vector<const char>(buffer.start(), 0);
-}
-
-
 static void CutToMaxSignificantDigits(Vector<const char> buffer,
                                        int exponent,
                                        char* significant_buffer,
@@ -202,12 +191,14 @@ static bool DoubleStrtod(Vector<const char> trimmed,
                          int exponent,
                          double* result) {
 #if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+  // Avoid "unused parameter" warnings
+  (void) trimmed;
+  (void) exponent;
+  (void) result;
   // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
   // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
   // result is not accurate.
   // We know that Windows32 uses 64 bits and is therefore accurate.
-  // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
-  // the same problem.
   return false;
 #else
   if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
@@ -458,6 +449,11 @@ static bool IsNonZeroDigit(const char d) {
   return ('1' <= d) && (d <= '9');
 }
 
+#ifdef __has_cpp_attribute
+#if __has_cpp_attribute(maybe_unused)
+[[maybe_unused]]
+#endif
+#endif
 static bool AssertTrimmedDigits(const Vector<const char>& buffer) {
   for(int i = 0; i < buffer.length(); ++i) {
     if(!IsDigit(buffer[i])) {
@@ -529,6 +525,12 @@ float Strtof(Vector<const char> buffer, int exponent) {
   TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
              &trimmed, &updated_exponent);
   exponent = updated_exponent;
+  return StrtofTrimmed(trimmed, exponent);
+}
+
+float StrtofTrimmed(Vector<const char> trimmed, int exponent) {
+  DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
+  DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
 
   double double_guess;
   bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
index ff0ee470923e93b763fc68f9ea5c02f0d52b9a78..77221fb9d5388f4fc869cdc40b345165c2a86872 100644 (file)
@@ -40,11 +40,25 @@ double Strtod(Vector<const char> buffer, int exponent);
 // contain a dot or a sign. It must not start with '0', and must not be empty.
 float Strtof(Vector<const char> buffer, int exponent);
 
-// For special use cases, the heart of the Strtod() function is also available
-// separately, it assumes that 'trimmed' is as produced by TrimAndCut(), i.e.
-// no leading or trailing zeros, also no lone zero, and not 'too many' digits.
+// Same as Strtod, but assumes that 'trimmed' is already trimmed, as if run
+// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
+// zeros, must not be a lone zero, and must not have 'too many' digits.
 double StrtodTrimmed(Vector<const char> trimmed, int exponent);
 
+// Same as Strtof, but assumes that 'trimmed' is already trimmed, as if run
+// through TrimAndCut. That is, 'trimmed' must have no leading or trailing
+// zeros, must not be a lone zero, and must not have 'too many' digits.
+float StrtofTrimmed(Vector<const char> trimmed, int exponent);
+
+inline Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
+  for (int i = buffer.length() - 1; i >= 0; --i) {
+    if (buffer[i] != '0') {
+      return buffer.SubVector(0, i + 1);
+    }
+  }
+  return Vector<const char>(buffer.start(), 0);
+}
+
 }  // namespace double_conversion
 
 #endif  // DOUBLE_CONVERSION_STRTOD_H_
index 438d0551c6d07e1d48f3b3d4338dec9b8621da54..c72c333f020a1a4b4b1a64fb2de346addb30a7f2 100644 (file)
@@ -108,7 +108,7 @@ int main(int argc, char** argv) {
     defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
     defined(__hppa__) || defined(__ia64__) || \
     defined(__mips__) || \
-    defined(__nios2__) || \
+    defined(__nios2__) || defined(__ghs) || \
     defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
     defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
     defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
index 650154b6e9ba32ad19a9c072aae37d184a861dff..325b7a1514146bbc29ce34db5bae29c00728e243 100644 (file)
@@ -438,7 +438,7 @@ TEST(DoubleToShortestSingle) {
 
 
 TEST(DoubleToFixed) {
-  const int kBufferSize = 128;
+  const int kBufferSize = 168;
   char buffer[kBufferSize];
   StringBuilder builder(buffer, kBufferSize);
   int flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
@@ -462,25 +462,98 @@ TEST(DoubleToFixed) {
   CHECK_EQ("0.0", builder.Finalize());
 
   DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxFixedDigitsBeforePoint == 60);
-  DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxFixedDigitsAfterPoint == 60);
+  DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxFixedDigitsAfterPoint == 100);
+
+  // Most of the 100 digit tests were copied from
+  // https://searchfox.org/mozilla-central/source/js/src/tests/non262/Number/toFixed-values.js.
+
   builder.Reset();
   CHECK(dc.ToFixed(
       0.0, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));
-  CHECK_EQ("0.000000000000000000000000000000000000000000000000000000000000",
+  CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            builder.Finalize());
 
   builder.Reset();
   CHECK(dc.ToFixed(
       9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));
   CHECK_EQ("899999999999999918767229449717619953810131273674690656206848."
-           "000000000000000000000000000000000000000000000000000000000000",
+           "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            builder.Finalize());
 
   builder.Reset();
   CHECK(dc.ToFixed(
       -9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));
   CHECK_EQ("-899999999999999918767229449717619953810131273674690656206848."
-           "000000000000000000000000000000000000000000000000000000000000",
+           "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(
+      1e-100, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));
+  CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(0.3000000000000000444089209850062616169452667236328125,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("0.3000000000000000444089209850062616169452667236328125000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(1.5e-100,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(1.15e-99,  // In reality: 1.14999999999999992147301128036734...
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(3.141592653589793,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(1.0,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(-123456.78,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("-123456.7799999999988358467817306518554687500000000000000000000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(123456.78,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("123456.7799999999988358467817306518554687500000000000000000000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(100000000000000000000.0,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("100000000000000000000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+           builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc.ToFixed(-100000000000000000000.0,
+                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
+                   &builder));
+  CHECK_EQ("-100000000000000000000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            builder.Finalize());
 
   builder.Reset();
@@ -637,6 +710,10 @@ TEST(DoubleToFixed) {
   CHECK(dc5.ToFixed(0.1, 30, &builder));
   CHECK_EQ("0.100000000000000005551115123126", builder.Finalize());
 
+  builder.Reset();
+  CHECK(dc5.ToFixed(0.1, 100, &builder));
+  CHECK_EQ("0.1000000000000000055511151231257827021181583404541015625000000000000000000000000000000000000000000000", builder.Finalize());
+
   builder.Reset();
   CHECK(dc5.ToFixed(0.1, 17, &builder));
   CHECK_EQ("0.10000000000000001", builder.Finalize());
@@ -861,6 +938,33 @@ TEST(DoubleToExponential) {
   builder.Reset();
   CHECK(dc4.ToExponential(-Double::NaN(), 1, &builder));
   CHECK_EQ("NaN", builder.Finalize());
+
+  // Test min_exponent_width
+  DoubleToStringConverter dc5(flags, NULL, NULL, 'e', 0, 0, 0, 0, 2);
+
+  builder.Reset();
+  CHECK(dc5.ToExponential(11111111111.0, 6, &builder));
+  CHECK_EQ("1.111111e10", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToExponential(1111111111.0, 6, &builder));
+  CHECK_EQ("1.111111e09", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToExponential(1111111.0, 6, &builder));
+  CHECK_EQ("1.111111e06", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToExponential(10000000000.0, 6, &builder));
+  CHECK_EQ("1.000000e10", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToExponential(1000000000.0, 6, &builder));
+  CHECK_EQ("1.000000e09", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToExponential(1.0, 6, &builder));
+  CHECK_EQ("1.000000e00", builder.Finalize());
 }
 
 
@@ -1063,6 +1167,98 @@ TEST(DoubleToPrecision) {
   builder.Reset();
   CHECK(dc7.ToPrecision(-Double::NaN(), 1, &builder));
   CHECK_EQ("NaN", builder.Finalize());
+
+  // Test NO_TRAILING_ZERO and its interaction with other flags.
+  flags = DoubleToStringConverter::NO_TRAILING_ZERO;
+  DoubleToStringConverter dc9(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1);
+  flags = DoubleToStringConverter::NO_TRAILING_ZERO |
+      DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT;
+  DoubleToStringConverter dc10(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1);
+  flags = DoubleToStringConverter::NO_TRAILING_ZERO |
+      DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |
+      DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;
+  DoubleToStringConverter dc11(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1);
+
+  builder.Reset();
+  CHECK(dc9.ToPrecision(230.001, 5, &builder));
+  CHECK_EQ("230", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc10.ToPrecision(230.001, 5, &builder));
+  CHECK_EQ("230.", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc11.ToPrecision(230.001, 5, &builder));
+  CHECK_EQ("230.0", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToPrecision(230.001, 5, &builder));
+  CHECK_EQ("230.00", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc9.ToPrecision(2300010, 5, &builder));
+  CHECK_EQ("2.3e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc10.ToPrecision(2300010, 5, &builder));
+  CHECK_EQ("2.3e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc11.ToPrecision(2300010, 5, &builder));
+  CHECK_EQ("2.3e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToPrecision(2300010, 5, &builder));
+  CHECK_EQ("2.3000e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc9.ToPrecision(0.02300010, 5, &builder));
+  CHECK_EQ("0.023", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc10.ToPrecision(0.02300010, 5, &builder));
+  CHECK_EQ("0.023", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc11.ToPrecision(0.02300010, 5, &builder));
+  CHECK_EQ("0.023", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToPrecision(0.02300010, 5, &builder));
+  CHECK_EQ("0.023000", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc9.ToPrecision(2000010, 5, &builder));
+  CHECK_EQ("2e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc10.ToPrecision(2000010, 5, &builder));
+  CHECK_EQ("2e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc11.ToPrecision(2000010, 5, &builder));
+  CHECK_EQ("2e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToPrecision(2000010, 5, &builder));
+  CHECK_EQ("2.0000e6", builder.Finalize());
+
+  // Test that rounding up still works with NO_TRAILING_ZERO
+  builder.Reset();
+  CHECK(dc9.ToPrecision(2000080, 5, &builder));
+  CHECK_EQ("2.0001e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc10.ToPrecision(2000080, 5, &builder));
+  CHECK_EQ("2.0001e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc11.ToPrecision(2000080, 5, &builder));
+  CHECK_EQ("2.0001e6", builder.Finalize());
+
+  builder.Reset();
+  CHECK(dc5.ToPrecision(2000080, 5, &builder));
+  CHECK_EQ("2.0001e6", builder.Finalize());
 }
 
 
index d1295aa5a1f5da23863c30e3c5c3e0b6c64d801a..b5a3bab7187d99b4dc6baf9625ff6232cf37c544 100644 (file)
@@ -55,6 +55,10 @@ static float StrtofChar(const char* str, int exponent) {
   return Strtof(StringToVector(str), exponent);
 }
 
+static float StrtofTrimmedChar(const char* str, int exponent) {
+  return StrtofTrimmed(StringToVector(str), exponent);
+}
+
 
 TEST(Strtod) {
   Vector<const char> vector;
@@ -876,6 +880,194 @@ TEST(Strtof) {
 
 }
 
+TEST(StrtofTrimmed) {
+  Vector<const char> vector;
+
+  vector = StringToVector("1");
+  CHECK_EQ(1.0f, StrtofTrimmed(vector, 0));
+  CHECK_EQ(10.0f, StrtofTrimmed(vector, 1));
+  CHECK_EQ(100.0f, StrtofTrimmed(vector, 2));
+  CHECK_EQ(1e20f, StrtofTrimmed(vector, 20));
+  CHECK_EQ(1e22f, StrtofTrimmed(vector, 22));
+  CHECK_EQ(1e23f, StrtofTrimmed(vector, 23));
+  CHECK_EQ(1e35f, StrtofTrimmed(vector, 35));
+  CHECK_EQ(1e36f, StrtofTrimmed(vector, 36));
+  CHECK_EQ(1e37f, StrtofTrimmed(vector, 37));
+  CHECK_EQ(1e-1f, StrtofTrimmed(vector, -1));
+  CHECK_EQ(1e-2f, StrtofTrimmed(vector, -2));
+  CHECK_EQ(1e-5f, StrtofTrimmed(vector, -5));
+  CHECK_EQ(1e-20f, StrtofTrimmed(vector, -20));
+  CHECK_EQ(1e-22f, StrtofTrimmed(vector, -22));
+  CHECK_EQ(1e-23f, StrtofTrimmed(vector, -23));
+  CHECK_EQ(1e-25f, StrtofTrimmed(vector, -25));
+  CHECK_EQ(1e-39f, StrtofTrimmed(vector, -39));
+
+  vector = StringToVector("2");
+  CHECK_EQ(2.0f, StrtofTrimmed(vector, 0));
+  CHECK_EQ(20.0f, StrtofTrimmed(vector, 1));
+  CHECK_EQ(200.0f, StrtofTrimmed(vector, 2));
+  CHECK_EQ(2e20f, StrtofTrimmed(vector, 20));
+  CHECK_EQ(2e22f, StrtofTrimmed(vector, 22));
+  CHECK_EQ(2e23f, StrtofTrimmed(vector, 23));
+  CHECK_EQ(2e35f, StrtofTrimmed(vector, 35));
+  CHECK_EQ(2e36f, StrtofTrimmed(vector, 36));
+  CHECK_EQ(2e37f, StrtofTrimmed(vector, 37));
+  CHECK_EQ(2e-1f, StrtofTrimmed(vector, -1));
+  CHECK_EQ(2e-2f, StrtofTrimmed(vector, -2));
+  CHECK_EQ(2e-5f, StrtofTrimmed(vector, -5));
+  CHECK_EQ(2e-20f, StrtofTrimmed(vector, -20));
+  CHECK_EQ(2e-22f, StrtofTrimmed(vector, -22));
+  CHECK_EQ(2e-23f, StrtofTrimmed(vector, -23));
+  CHECK_EQ(2e-25f, StrtofTrimmed(vector, -25));
+  CHECK_EQ(2e-39f, StrtofTrimmed(vector, -39));
+
+  vector = StringToVector("9");
+  CHECK_EQ(9.0f, StrtofTrimmed(vector, 0));
+  CHECK_EQ(90.0f, StrtofTrimmed(vector, 1));
+  CHECK_EQ(900.0f, StrtofTrimmed(vector, 2));
+  CHECK_EQ(9e20f, StrtofTrimmed(vector, 20));
+  CHECK_EQ(9e22f, StrtofTrimmed(vector, 22));
+  CHECK_EQ(9e23f, StrtofTrimmed(vector, 23));
+  CHECK_EQ(9e35f, StrtofTrimmed(vector, 35));
+  CHECK_EQ(9e36f, StrtofTrimmed(vector, 36));
+  CHECK_EQ(9e37f, StrtofTrimmed(vector, 37));
+  CHECK_EQ(9e-1f, StrtofTrimmed(vector, -1));
+  CHECK_EQ(9e-2f, StrtofTrimmed(vector, -2));
+  CHECK_EQ(9e-5f, StrtofTrimmed(vector, -5));
+  CHECK_EQ(9e-20f, StrtofTrimmed(vector, -20));
+  CHECK_EQ(9e-22f, StrtofTrimmed(vector, -22));
+  CHECK_EQ(9e-23f, StrtofTrimmed(vector, -23));
+  CHECK_EQ(9e-25f, StrtofTrimmed(vector, -25));
+  CHECK_EQ(9e-39f, StrtofTrimmed(vector, -39));
+
+  vector = StringToVector("12345");
+  CHECK_EQ(12345.0f, StrtofTrimmed(vector, 0));
+  CHECK_EQ(123450.0f, StrtofTrimmed(vector, 1));
+  CHECK_EQ(1234500.0f, StrtofTrimmed(vector, 2));
+  CHECK_EQ(12345e20f, StrtofTrimmed(vector, 20));
+  CHECK_EQ(12345e22f, StrtofTrimmed(vector, 22));
+  CHECK_EQ(12345e23f, StrtofTrimmed(vector, 23));
+  CHECK_EQ(12345e30f, StrtofTrimmed(vector, 30));
+  CHECK_EQ(12345e31f, StrtofTrimmed(vector, 31));
+  CHECK_EQ(12345e32f, StrtofTrimmed(vector, 32));
+  CHECK_EQ(12345e-1f, StrtofTrimmed(vector, -1));
+  CHECK_EQ(12345e-2f, StrtofTrimmed(vector, -2));
+  CHECK_EQ(12345e-5f, StrtofTrimmed(vector, -5));
+  CHECK_EQ(12345e-20f, StrtofTrimmed(vector, -20));
+  CHECK_EQ(12345e-22f, StrtofTrimmed(vector, -22));
+  CHECK_EQ(12345e-23f, StrtofTrimmed(vector, -23));
+  CHECK_EQ(12345e-25f, StrtofTrimmed(vector, -25));
+  CHECK_EQ(12345e-39f, StrtofTrimmed(vector, -39));
+
+  vector = StringToVector("12345678901234");
+  CHECK_EQ(12345678901234.0f, StrtofTrimmed(vector, 0));
+  CHECK_EQ(123456789012340.0f, StrtofTrimmed(vector, 1));
+  CHECK_EQ(1234567890123400.0f, StrtofTrimmed(vector, 2));
+  CHECK_EQ(12345678901234e20f, StrtofTrimmed(vector, 20));
+  CHECK_EQ(12345678901234e22f, StrtofTrimmed(vector, 22));
+  CHECK_EQ(12345678901234e23f, StrtofTrimmed(vector, 23));
+  CHECK_EQ(12345678901234e-1f, StrtofTrimmed(vector, -1));
+  CHECK_EQ(12345678901234e-2f, StrtofTrimmed(vector, -2));
+  CHECK_EQ(12345678901234e-5f, StrtofTrimmed(vector, -5));
+  CHECK_EQ(12345678901234e-20f, StrtofTrimmed(vector, -20));
+  CHECK_EQ(12345678901234e-22f, StrtofTrimmed(vector, -22));
+  CHECK_EQ(12345678901234e-23f, StrtofTrimmed(vector, -23));
+  CHECK_EQ(12345678901234e-25f, StrtofTrimmed(vector, -25));
+  CHECK_EQ(12345678901234e-39f, StrtofTrimmed(vector, -39));
+
+  vector = StringToVector("123456789012345");
+  CHECK_EQ(123456789012345.0f, StrtofTrimmed(vector, 0));
+  CHECK_EQ(1234567890123450.0f, StrtofTrimmed(vector, 1));
+  CHECK_EQ(12345678901234500.0f, StrtofTrimmed(vector, 2));
+  CHECK_EQ(123456789012345e20f, StrtofTrimmed(vector, 20));
+  CHECK_EQ(123456789012345e22f, StrtofTrimmed(vector, 22));
+  CHECK_EQ(123456789012345e23f, StrtofTrimmed(vector, 23));
+  CHECK_EQ(123456789012345e-1f, StrtofTrimmed(vector, -1));
+  CHECK_EQ(123456789012345e-2f, StrtofTrimmed(vector, -2));
+  CHECK_EQ(123456789012345e-5f, StrtofTrimmed(vector, -5));
+  CHECK_EQ(123456789012345e-20f, StrtofTrimmed(vector, -20));
+  CHECK_EQ(123456789012345e-22f, StrtofTrimmed(vector, -22));
+  CHECK_EQ(123456789012345e-23f, StrtofTrimmed(vector, -23));
+  CHECK_EQ(123456789012345e-25f, StrtofTrimmed(vector, -25));
+  CHECK_EQ(123456789012345e-39f, StrtofTrimmed(vector, -39));
+
+  CHECK_EQ(0.0f, StrtofTrimmedChar("", 1324));
+  CHECK_EQ(0.0f, StrtofTrimmedChar("2", -324));
+  CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45));
+  // It would be more readable to put non-zero literals on the left side (i.e.
+  //   CHECK_EQ(1e-46, StrtofChar("1", -45))), but then Gcc complains that
+  // they are truncated to zero.
+  CHECK_EQ(0.0f, StrtofTrimmedChar("1", -46));
+  CHECK_EQ(0.0f, StrtofTrimmedChar("1", -47));
+  CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45));
+  CHECK_EQ(1e-45f, StrtofTrimmedChar("8", -46));
+
+  // It would be more readable to put the literals (and not Double::Infinity())
+  // on the left side (i.e. CHECK_EQ(3e38, StrtofChar("3", 38))), but then Gcc
+  // complains that the floating constant exceeds range of 'double'.
+  CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("3", 39));
+  CHECK_EQ(3e38f, StrtofTrimmedChar("3", 38));
+  CHECK_EQ(3401e35f, StrtofTrimmedChar("3401", 35));
+  CHECK_EQ(3401e34f, StrtofTrimmedChar("3401", 34));
+  CHECK_EQ(34e37f, StrtofTrimmedChar("34", 37));
+  CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235676", 28));
+  CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235677", 28));
+  CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("34028235678", 28));
+
+  // The following number is the result of 89255.0/1e-22. Both floating-point
+  // numbers can be accurately represented with doubles. However on Linux,x86
+  // the floating-point stack is set to 80bits and the double-rounding
+  // introduces an error.
+  CHECK_EQ(89255e-22f, StrtofTrimmedChar("89255", -22));
+
+  // Boundary cases. Boundaries themselves should round to even.
+  //
+  // 0x4f012334 = 2166567936
+  //      next:   2166568192
+  //  boundary:   2166568064 should round down.
+  CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166567936", 0));
+  CHECK_EQ(2166568192.0f, StrtofTrimmedChar("2166568192", 0));
+  CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166568064", 0));
+  CHECK_EQ(2166567936.0f, StrtofTrimmedChar("216656806399999", -5));
+  CHECK_EQ(2166568192.0f, StrtofTrimmedChar("216656806400001", -5));
+  // Verify that we don't double round.
+  // Get the boundary of the boundary.
+  CHECK_EQ(2.1665680640000002384185791015625e9, 2166568064.0);
+  // Visual Studio gets this wrong and believes that these two numbers are the
+  // same doubles. We want to test our conversion and not the compiler. We
+  // therefore disable the check.
+#ifndef _MSC_VER
+  CHECK(2.16656806400000023841857910156251e9 != 2166568064.0);
+#endif
+  CHECK_EQ(2166568192.0f, StrtofTrimmedChar("21665680640000002384185791015625", -22));
+
+  // 0x4fffffff = 8589934080
+  //      next:   8589934592
+  //  boundary:   8589934336 should round up.
+  CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934592", 0));
+  CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934336", 0));
+  CHECK_EQ(8589934080.0f, StrtofTrimmedChar("858993433599999", -5));
+  CHECK_EQ(8589934592.0f, StrtofTrimmedChar("858993433600001", -5));
+  // Verify that we don't double round.
+  // Get the boundary of the boundary.
+  // Visual Studio gets this wrong. To avoid failing tests because of a broken
+  // compiler we disable the following two tests. They were only testing the
+  // compiler. The real test is still active.
+#ifndef _MSC_VER
+  CHECK_EQ(8.589934335999999523162841796875e+09, 8589934336.0);
+  CHECK(8.5899343359999995231628417968749e+09 != 8589934336.0);
+#endif
+  CHECK_EQ(8589934080.0f, StrtofTrimmedChar("8589934335999999523162841796875", -21));
+
+  // 0x4f000000 = 2147483648
+  //      next:   2147483904
+  //  boundary:   2147483776 should round down.
+  CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483648", 0));
+  CHECK_EQ(2147483904.0f, StrtofTrimmedChar("2147483904", 0));
+  CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483776", 0));
+  CHECK_EQ(2147483648.0f, StrtofTrimmedChar("214748377599999", -5));
+  CHECK_EQ(2147483904.0f, StrtofTrimmedChar("214748377600001", -5));
+}
 
 static int CompareBignumToDiyFp(const Bignum& bignum_digits,
                                 int bignum_exponent,