Use grisu for exponent notation

This commit is contained in:
Victor Zverovich 2019-11-19 15:18:38 -08:00
parent e9bff78814
commit 66d7746bb3
2 changed files with 28 additions and 23 deletions

View File

@ -1123,6 +1123,9 @@ template <typename Char> class grisu_writer {
*it++ = static_cast<Char>(*digits_);
if (num_digits_ > 1) *it++ = decimal_point_;
it = copy_str<Char>(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<Char>('0'));
*it++ = static_cast<Char>(params_.upper ? 'E' : 'e');
return write_exponent<Char>(full_exp - 1, it);
}
@ -2808,8 +2811,7 @@ template <typename T, bool USE_GRISU>
void internal::basic_writer<Range>::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<Range>::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<double>(value), buffer, precision, options, exp);
bool use_grisu = USE_GRISU && (specs.type != 'a' && specs.type != 'A') &&
grisu_format(static_cast<double>(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<Range>::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<int>(buffer.size());
write_padded(as, grisu_writer<char_type>(buffer.data(), num_digits, exp,
params, decimal_point));
@ -3602,20 +3606,20 @@ FMT_CONSTEXPR internal::udl_arg<wchar_t> 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<std::remove_pointer< \
typename std::decay<decltype(s)>::type>::type>::type; \
__VA_ARGS__ FMT_CONSTEXPR \
operator fmt::basic_string_view<char_type>() const { \
return {s, sizeof(s) / sizeof(char_type) - 1}; \
} \
} result; \
/* Suppress Qt Creator warning about unused operator. */ \
(void)static_cast<fmt::basic_string_view<typename str::char_type>>( \
result); \
return result; \
#define FMT_STRING_IMPL(s, ...) \
[] { \
struct str : fmt::compile_string { \
using char_type = typename std::remove_cv<std::remove_pointer< \
typename std::decay<decltype(s)>::type>::type>::type; \
__VA_ARGS__ FMT_CONSTEXPR \
operator fmt::basic_string_view<char_type>() const { \
return {s, sizeof(s) / sizeof(char_type) - 1}; \
} \
} result; \
/* Suppress Qt Creator warning about unused operator. */ \
(void)static_cast<fmt::basic_string_view<typename str::char_type>>( \
result); \
return result; \
}()
/**

View File

@ -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<void*>(0xcafe)),
format_error,