Add a flag to make precision mode like printf's %g (#149)
With this, %g can be emulated with:
```
DoubleToStringConverter cvt(
UNIQUE_ZERO | NO_TRAILING_ZERO | EMIT_POSITIVE_EXPONENT_SIGN,
"inf", "nan", 'e', 0, 0, 4, 0, 2)
```
diff --git a/double-conversion/double-to-string.cc b/double-conversion/double-to-string.cc
index d9be42d..9255bce 100644
--- a/double-conversion/double-to-string.cc
+++ b/double-conversion/double-to-string.cc
@@ -327,9 +327,21 @@
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.
diff --git a/double-conversion/double-to-string.h b/double-conversion/double-to-string.h
index 7f866f8..6317a08 100644
--- a/double-conversion/double-to-string.h
+++ b/double-conversion/double-to-string.h
@@ -77,7 +77,8 @@
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.
@@ -89,9 +90,13 @@
// 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
diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc
index c117aa7..ab65cc3 100644
--- a/test/cctest/test-conversions.cc
+++ b/test/cctest/test-conversions.cc
@@ -1090,6 +1090,98 @@
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());
}