Skip to content

Commit

Permalink
Don't emit more than precision digits (#1072)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Mar 9, 2019
1 parent 3466d9c commit 49d244c
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 6 deletions.
16 changes: 11 additions & 5 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
uint64_t fractional = value.f & (one.f - 1);
exp = count_digits(integral); // kappa in Grisu.
stop.on_exp(exp);
int size = 0;
if (stop.on_exp(exp)) return size;
// Generate digits for the integral part. This can produce up to 10 digits.
do {
uint32_t digit = 0;
Expand Down Expand Up @@ -537,17 +537,23 @@ struct fixed_stop {
int exp10;
bool fixed;

void on_exp(int exp) {
if (!fixed) return;
bool enough_precision(int full_exp) const {
return full_exp <= 0 && -full_exp >= precision;
}

bool on_exp(int exp) {
if (!fixed) return false;
exp += exp10;
if (exp >= 0) precision += exp;
// TODO: round
return enough_precision(exp);
}

// 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 (size != precision && !enough_precision(exp + exp10)) return false;
if (!integral) {
// Check if error * 2 < divisor with overflow prevention.
// The check is not needed for the integral part because error = 1
Expand Down Expand Up @@ -585,7 +591,7 @@ struct fixed_stop {
struct shortest_stop {
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,
uint64_t error, int& exp, bool integral) {
Expand Down
2 changes: 1 addition & 1 deletion include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2892,7 +2892,7 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
int exp = 0;
int precision = spec.has_precision() || !spec.type ? spec.precision : 6;
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);
Expand Down
4 changes: 4 additions & 0 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,10 @@ TEST(FormatterTest, FormatDouble) {
EXPECT_EQ(buffer, format("{:A}", -42.0));
}

TEST(FormatterTest, PrecisionRounding) {
EXPECT_EQ("0.000", format("{:.3f}", 0.00049));
}

TEST(FormatterTest, FormatNaN) {
double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", format("{}", nan));
Expand Down

0 comments on commit 49d244c

Please sign in to comment.