mirror of
https://github.com/fmtlib/fmt.git
synced 2025-01-09 22:20:06 +00:00
Implement rounding up and clean up FP formatting
This commit is contained in:
parent
d560ddac25
commit
93d22dec35
@ -515,8 +515,9 @@ int grisu2_gen_digits(char* buf, fp value, uint64_t error_ulp, int& exp,
|
||||
uint64_t remainder =
|
||||
(static_cast<uint64_t>(integral) << -one.e) + fractional;
|
||||
if (stop(buf, size, remainder, data::POWERS_OF_10_64[exp] << -one.e,
|
||||
error_ulp, exp, true))
|
||||
error_ulp, exp, true)) {
|
||||
return size;
|
||||
}
|
||||
} while (exp > 0);
|
||||
// Generate digits for the fractional part.
|
||||
for (;;) {
|
||||
@ -542,8 +543,9 @@ struct fixed_stop {
|
||||
if (exp >= 0) precision += exp;
|
||||
}
|
||||
|
||||
bool operator()(char*, int& size, uint64_t remainder, uint64_t divisor,
|
||||
uint64_t error, int&, bool integral) {
|
||||
// TODO: test
|
||||
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
||||
uint64_t error, int& exp, bool integral) {
|
||||
assert(remainder < divisor);
|
||||
if (size != precision) return false;
|
||||
if (!integral) {
|
||||
@ -560,7 +562,20 @@ struct fixed_stop {
|
||||
// Round down if (remainder + error) * 2 <= divisor.
|
||||
if (remainder < divisor - remainder && error * 2 <= divisor - remainder * 2)
|
||||
return true;
|
||||
// TODO: round up
|
||||
// Round up if (remainder - error) * 2 >= divisor.
|
||||
if (remainder >= error &&
|
||||
remainder - error >= divisor - (remainder - error)) {
|
||||
++buf[size - 1];
|
||||
for (int i = size - 1; i > 0 && buf[i] > '9'; --i) {
|
||||
buf[i] = '0';
|
||||
++buf[i - 1];
|
||||
}
|
||||
if (buf[0] > '9') {
|
||||
buf[0] = '1';
|
||||
++exp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size = -1;
|
||||
return true;
|
||||
}
|
||||
|
@ -1178,10 +1178,10 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
|
||||
|
||||
// The number is given as v = digits * pow(10, exp).
|
||||
template <typename Char, typename It>
|
||||
It grisu2_prettify(const char* digits, int size, int exp, It it) {
|
||||
It grisu2_prettify(const char* digits, int size, int exp, It it,
|
||||
gen_digits_params params) {
|
||||
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
||||
int full_exp = size + exp;
|
||||
auto params = gen_digits_params();
|
||||
params.fixed = (full_exp - 1) >= -4 && (full_exp - 1) <= 10;
|
||||
if (!params.fixed) {
|
||||
// Insert a decimal point after the first digit and add an exponent.
|
||||
@ -1194,7 +1194,6 @@ It grisu2_prettify(const char* digits, int size, int exp, It it) {
|
||||
*it++ = static_cast<Char>(params.upper ? 'E' : 'e');
|
||||
return write_exponent<Char>(exp, it);
|
||||
}
|
||||
params.trailing_zeros = true;
|
||||
const int exp_threshold = 21;
|
||||
if (size <= full_exp && full_exp <= exp_threshold) {
|
||||
// 1234e7 -> 12340000000[.0+]
|
||||
@ -2682,13 +2681,16 @@ template <typename Range> class basic_writer {
|
||||
size_t size_;
|
||||
char sign_;
|
||||
int exp_;
|
||||
internal::gen_digits_params params_;
|
||||
|
||||
public:
|
||||
grisu_writer(char sign, internal::buffer& digits, int exp)
|
||||
: digits_(digits), sign_(sign), exp_(exp) {
|
||||
grisu_writer(char sign, internal::buffer& digits, int exp,
|
||||
const internal::gen_digits_params& params)
|
||||
: digits_(digits), sign_(sign), exp_(exp), params_(params) {
|
||||
int num_digits = static_cast<int>(digits.size());
|
||||
auto it = internal::grisu2_prettify<char>(
|
||||
digits.data(), num_digits, exp, internal::counting_iterator<char>());
|
||||
digits.data(), num_digits, exp, internal::counting_iterator<char>(),
|
||||
params_);
|
||||
size_ = it.count();
|
||||
}
|
||||
|
||||
@ -2699,7 +2701,7 @@ template <typename Range> class basic_writer {
|
||||
if (sign_) *it++ = static_cast<char_type>(sign_);
|
||||
int num_digits = static_cast<int>(digits_.size());
|
||||
it = internal::grisu2_prettify<char_type>(digits_.data(), num_digits,
|
||||
exp_, it);
|
||||
exp_, it, params_);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2855,8 +2857,7 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
|
||||
internal::handle_float_type_spec(handler.type, handler);
|
||||
|
||||
char sign = 0;
|
||||
// Use signbit instead of value < 0 because the latter is always
|
||||
// false for NaN.
|
||||
// Use signbit instead of value < 0 since the latter is always false for NaN.
|
||||
if (std::signbit(value)) {
|
||||
sign = '-';
|
||||
value = -value;
|
||||
@ -2874,21 +2875,20 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
|
||||
}
|
||||
} write_inf_or_nan = {*this, spec, sign, handler.as_percentage};
|
||||
|
||||
// Format NaN and ininity ourselves because sprintf's output is not consistent
|
||||
// Format ininity and NaN ourselves because sprintf's output is not consistent
|
||||
// across platforms.
|
||||
if (internal::fputil::isnotanumber(value))
|
||||
return write_inf_or_nan(handler.upper ? "NAN" : "nan");
|
||||
if (internal::fputil::isinfinity(value))
|
||||
return write_inf_or_nan(handler.upper ? "INF" : "inf");
|
||||
if (internal::fputil::isnotanumber(value))
|
||||
return write_inf_or_nan(handler.upper ? "NAN" : "nan");
|
||||
|
||||
if (handler.as_percentage) value *= 100;
|
||||
|
||||
memory_buffer buffer;
|
||||
int exp = 0;
|
||||
int precision = spec.has_precision() || !spec.type ? spec.precision : 6;
|
||||
|
||||
if (handler.as_percentage) value *= 100.;
|
||||
|
||||
bool use_grisu = fmt::internal::use_grisu<T>() &&
|
||||
!spec.type &&
|
||||
(!spec.type || handler.fixed) &&
|
||||
internal::grisu2_format(static_cast<double>(value), buffer,
|
||||
precision, handler.fixed, exp);
|
||||
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
||||
@ -2909,10 +2909,13 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
|
||||
} else if (spec.align() == ALIGN_DEFAULT) {
|
||||
as.align_ = ALIGN_RIGHT;
|
||||
}
|
||||
if (use_grisu)
|
||||
write_padded(as, grisu_writer{sign, buffer, exp});
|
||||
else
|
||||
if (use_grisu) {
|
||||
auto params = internal::gen_digits_params();
|
||||
if (precision != 0) params.trailing_zeros = true;
|
||||
write_padded(as, grisu_writer{sign, buffer, exp, params});
|
||||
} else {
|
||||
write_padded(as, double_writer{sign, buffer});
|
||||
}
|
||||
}
|
||||
|
||||
// Reports a system error without throwing an exception.
|
||||
|
Loading…
Reference in New Issue
Block a user