From 66d7746bb399d8b7fac43e34be80bd14a1c1ee38 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 19 Nov 2019 15:18:38 -0800 Subject: [PATCH] Use grisu for exponent notation --- include/fmt/format.h | 50 ++++++++++++++++++++++++-------------------- test/format-test.cc | 1 + 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 4126ab4b..6191592c 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1123,6 +1123,9 @@ template class grisu_writer { *it++ = static_cast(*digits_); if (num_digits_ > 1) *it++ = decimal_point_; it = copy_str(digits_ + 1, digits_ + num_digits_, it); + int num_zeros = params_.num_digits - num_digits_; + if (num_zeros > 0 && params_.trailing_zeros) + it = std::fill_n(it, num_zeros, static_cast('0')); *it++ = static_cast(params_.upper ? 'E' : 'e'); return write_exponent(full_exp - 1, it); } @@ -2808,8 +2811,7 @@ template void internal::basic_writer::write_fp(T value, const format_specs& specs) { auto sign = specs.sign; - // Use signbit instead of value < 0 since the latter is always false for NaN. - if (std::signbit(value)) { + if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. sign = sign::minus; value = -value; } else if (sign == sign::minus) { @@ -2828,15 +2830,15 @@ void internal::basic_writer::write_fp(T value, memory_buffer buffer; int exp = 0; int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; + int num_digits = + fspec.format == float_format::exp ? precision + 1 : precision; unsigned options = 0; if (fspec.format == float_format::fixed) options |= grisu_options::fixed; if (const_check(sizeof(value) == sizeof(float))) options |= grisu_options::binary32; - bool use_grisu = - USE_GRISU && - (specs.type != 'a' && specs.type != 'A' && specs.type != 'e' && - specs.type != 'E') && - grisu_format(static_cast(value), buffer, precision, options, exp); + bool use_grisu = USE_GRISU && (specs.type != 'a' && specs.type != 'A') && + grisu_format(static_cast(value), buffer, num_digits, + options, exp); char* decimal_point_pos = nullptr; if (!use_grisu) decimal_point_pos = sprintf_format(value, buffer, specs); @@ -2863,11 +2865,13 @@ void internal::basic_writer::write_fp(T value, auto params = gen_digits_params(); params.sign = sign; params.format = fspec.format; - params.num_digits = precision; + params.num_digits = num_digits; params.trailing_zeros = (precision != 0 && - (fspec.format == float_format::fixed || !specs.type)) || + (!specs.type || fspec.format == float_format::fixed || + fspec.format == float_format::exp)) || specs.alt; + params.upper = fspec.upper; int num_digits = static_cast(buffer.size()); write_padded(as, grisu_writer(buffer.data(), num_digits, exp, params, decimal_point)); @@ -3602,20 +3606,20 @@ FMT_CONSTEXPR internal::udl_arg operator"" _a(const wchar_t* s, #endif // FMT_USE_USER_DEFINED_LITERALS FMT_END_NAMESPACE -#define FMT_STRING_IMPL(s, ...) \ - [] { \ - struct str : fmt::compile_string { \ - using char_type = typename std::remove_cv::type>::type>::type; \ - __VA_ARGS__ FMT_CONSTEXPR \ - operator fmt::basic_string_view() const { \ - return {s, sizeof(s) / sizeof(char_type) - 1}; \ - } \ - } result; \ - /* Suppress Qt Creator warning about unused operator. */ \ - (void)static_cast>( \ - result); \ - return result; \ +#define FMT_STRING_IMPL(s, ...) \ + [] { \ + struct str : fmt::compile_string { \ + using char_type = typename std::remove_cv::type>::type>::type; \ + __VA_ARGS__ FMT_CONSTEXPR \ + operator fmt::basic_string_view() const { \ + return {s, sizeof(s) / sizeof(char_type) - 1}; \ + } \ + } result; \ + /* Suppress Qt Creator warning about unused operator. */ \ + (void)static_cast>( \ + result); \ + return result; \ }() /** diff --git a/test/format-test.cc b/test/format-test.cc index 08828ccb..4ed4d43a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1206,6 +1206,7 @@ TEST(FormatterTest, Precision) { "precision not allowed for this argument type"); EXPECT_EQ("1.2", format("{0:.2}", 1.2345)); EXPECT_EQ("1.2", format("{0:.2}", 1.2345l)); + EXPECT_EQ("1.2e+56", format("{:.2}", 1.234e56)); EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast(0xcafe)), format_error,