Don't emit more than precision digits (#1072)
This commit is contained in:
parent
3466d9c845
commit
49d244c065
@ -459,8 +459,8 @@ int grisu2_gen_digits(char* buf, fp value, uint64_t error_ulp, int& exp,
|
|||||||
// The fractional part of scaled value (p2 in Grisu) c = value % one.
|
// The fractional part of scaled value (p2 in Grisu) c = value % one.
|
||||||
uint64_t fractional = value.f & (one.f - 1);
|
uint64_t fractional = value.f & (one.f - 1);
|
||||||
exp = count_digits(integral); // kappa in Grisu.
|
exp = count_digits(integral); // kappa in Grisu.
|
||||||
stop.on_exp(exp);
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
if (stop.on_exp(exp)) return size;
|
||||||
// Generate digits for the integral part. This can produce up to 10 digits.
|
// Generate digits for the integral part. This can produce up to 10 digits.
|
||||||
do {
|
do {
|
||||||
uint32_t digit = 0;
|
uint32_t digit = 0;
|
||||||
@ -537,17 +537,23 @@ struct fixed_stop {
|
|||||||
int exp10;
|
int exp10;
|
||||||
bool fixed;
|
bool fixed;
|
||||||
|
|
||||||
void on_exp(int exp) {
|
bool enough_precision(int full_exp) const {
|
||||||
if (!fixed) return;
|
return full_exp <= 0 && -full_exp >= precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool on_exp(int exp) {
|
||||||
|
if (!fixed) return false;
|
||||||
exp += exp10;
|
exp += exp10;
|
||||||
if (exp >= 0) precision += exp;
|
if (exp >= 0) precision += exp;
|
||||||
|
// TODO: round
|
||||||
|
return enough_precision(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test
|
// TODO: test
|
||||||
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
||||||
uint64_t error, int& exp, bool integral) {
|
uint64_t error, int& exp, bool integral) {
|
||||||
assert(remainder < divisor);
|
assert(remainder < divisor);
|
||||||
if (size != precision) return false;
|
if (size != precision && !enough_precision(exp + exp10)) return false;
|
||||||
if (!integral) {
|
if (!integral) {
|
||||||
// Check if error * 2 < divisor with overflow prevention.
|
// Check if error * 2 < divisor with overflow prevention.
|
||||||
// The check is not needed for the integral part because error = 1
|
// The check is not needed for the integral part because error = 1
|
||||||
@ -585,7 +591,7 @@ struct fixed_stop {
|
|||||||
struct shortest_stop {
|
struct shortest_stop {
|
||||||
fp diff; // wp_w in Grisu.
|
fp diff; // wp_w in Grisu.
|
||||||
|
|
||||||
void on_exp(int) {}
|
bool on_exp(int) { return false; }
|
||||||
|
|
||||||
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
||||||
uint64_t error, int& exp, bool integral) {
|
uint64_t error, int& exp, bool integral) {
|
||||||
|
@ -2892,7 +2892,7 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
|
|||||||
int exp = 0;
|
int exp = 0;
|
||||||
int precision = spec.has_precision() || !spec.type ? spec.precision : 6;
|
int precision = spec.has_precision() || !spec.type ? spec.precision : 6;
|
||||||
bool use_grisu = fmt::internal::use_grisu<T>() &&
|
bool use_grisu = fmt::internal::use_grisu<T>() &&
|
||||||
!spec.type &&
|
(!spec.type || handler.fixed) &&
|
||||||
internal::grisu2_format(static_cast<double>(value), buffer,
|
internal::grisu2_format(static_cast<double>(value), buffer,
|
||||||
precision, handler.fixed, exp);
|
precision, handler.fixed, exp);
|
||||||
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
||||||
|
@ -1470,6 +1470,10 @@ TEST(FormatterTest, FormatDouble) {
|
|||||||
EXPECT_EQ(buffer, format("{:A}", -42.0));
|
EXPECT_EQ(buffer, format("{:A}", -42.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, PrecisionRounding) {
|
||||||
|
EXPECT_EQ("0.000", format("{:.3f}", 0.00049));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatNaN) {
|
TEST(FormatterTest, FormatNaN) {
|
||||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
EXPECT_EQ("nan", format("{}", nan));
|
EXPECT_EQ("nan", format("{}", nan));
|
||||||
|
Loading…
Reference in New Issue
Block a user