More tests and fixed precision fixes
This commit is contained in:
parent
287342dab1
commit
a82b3680dc
@ -571,41 +571,37 @@ struct fixed_handler {
|
|||||||
int exp10;
|
int exp10;
|
||||||
bool fixed;
|
bool fixed;
|
||||||
|
|
||||||
bool enough_precision(int full_exp) const {
|
|
||||||
return /*full_exp <= 0 &&*/ -full_exp >= precision;
|
|
||||||
}
|
|
||||||
|
|
||||||
digits::result on_start(uint64_t divisor, uint64_t remainder, uint64_t error,
|
digits::result on_start(uint64_t divisor, uint64_t remainder, uint64_t error,
|
||||||
int& exp) {
|
int& exp) {
|
||||||
// Non-fixed formats require at least one digit and no precision adjustment.
|
// Non-fixed formats require at least one digit and no precision adjustment.
|
||||||
if (!fixed) return digits::more;
|
if (!fixed) return digits::more;
|
||||||
int full_exp = exp + exp10;
|
// Adjust fixed precision by exponent because it is relative to decimal
|
||||||
// Increase precision by the number of integer digits, e.g.
|
// point.
|
||||||
// format("{:.2f}", 1.23) should produce "1.23", not "1.2".
|
precision += exp + exp10;
|
||||||
if (full_exp > 0) precision += full_exp;
|
// Check if precision is satisfied just by leading zeros, e.g.
|
||||||
if (!enough_precision(full_exp)) return digits::more;
|
// format("{:.2f}", 0.001) gives "0.00" without generating any digits.
|
||||||
|
if (precision > 0) return digits::more;
|
||||||
auto dir = get_round_direction(divisor, remainder, error);
|
auto dir = get_round_direction(divisor, remainder, error);
|
||||||
if (dir == unknown) return digits::error;
|
if (dir == unknown) return digits::error;
|
||||||
buf[size++] = dir == up ? '1' : '0';
|
buf[size++] = dir == up ? '1' : '0';
|
||||||
return digits::done;
|
return digits::done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test
|
|
||||||
digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder,
|
digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder,
|
||||||
uint64_t error, int& exp, bool integral) {
|
uint64_t error, int& exp, bool integral) {
|
||||||
assert(remainder < divisor);
|
FMT_ASSERT(remainder < divisor, "");
|
||||||
buf[size++] = digit;
|
buf[size++] = digit;
|
||||||
if (size != precision && !enough_precision(exp + exp10))
|
if (size != precision) return digits::more;
|
||||||
return digits::more;
|
|
||||||
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
|
||||||
// and divisor > (1 << 32) there.
|
// and divisor > (1 << 32) there.
|
||||||
if (error >= divisor || error >= divisor - error) return digits::error;
|
if (error >= divisor || error >= divisor - error) return digits::error;
|
||||||
} else {
|
} else {
|
||||||
assert(error == 1 && divisor > 2);
|
FMT_ASSERT(error == 1 && divisor > 2, "");
|
||||||
}
|
}
|
||||||
auto dir = get_round_direction(divisor, remainder, error);
|
auto dir = get_round_direction(divisor, remainder, error);
|
||||||
|
// TODO: test rounding
|
||||||
if (dir != up) return dir == down ? digits::done : digits::error;
|
if (dir != up) return dir == down ? digits::done : digits::error;
|
||||||
++buf[size - 1];
|
++buf[size - 1];
|
||||||
for (int i = size - 1; i > 0 && buf[i] > '9'; --i) {
|
for (int i = size - 1; i > 0 && buf[i] > '9'; --i) {
|
||||||
|
@ -121,6 +121,28 @@ TEST(FPTest, GetRoundDirection) {
|
|||||||
EXPECT_EQ(fmt::internal::up, get_round_direction(max, max - 1, 1));
|
EXPECT_EQ(fmt::internal::up, get_round_direction(max, max - 1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FPTest, FixedHandler) {
|
||||||
|
struct handler : fmt::internal::fixed_handler {
|
||||||
|
char buffer[10];
|
||||||
|
handler(int prec = 0) : fmt::internal::fixed_handler() {
|
||||||
|
buf = buffer;
|
||||||
|
precision = prec;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int exp = 0;
|
||||||
|
handler().on_digit('0', 100, 99, 0, exp, false);
|
||||||
|
EXPECT_THROW(handler().on_digit('0', 100, 100, 0, exp, false),
|
||||||
|
assertion_failure);
|
||||||
|
namespace digits = fmt::internal::digits;
|
||||||
|
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::done);
|
||||||
|
// Check that divisor - error doesn't overflow.
|
||||||
|
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, false), digits::error);
|
||||||
|
// Check that 2 * error doesn't overflow.
|
||||||
|
uint64_t max = std::numeric_limits<uint64_t>::max();
|
||||||
|
EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, exp, false),
|
||||||
|
digits::error);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
||||||
fmt::memory_buffer buf;
|
fmt::memory_buffer buf;
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
|
@ -1474,6 +1474,9 @@ TEST(FormatterTest, PrecisionRounding) {
|
|||||||
EXPECT_EQ("0", format("{:.0f}", 0.1));
|
EXPECT_EQ("0", format("{:.0f}", 0.1));
|
||||||
EXPECT_EQ("0.000", format("{:.3f}", 0.00049));
|
EXPECT_EQ("0.000", format("{:.3f}", 0.00049));
|
||||||
EXPECT_EQ("0.001", format("{:.3f}", 0.0005));
|
EXPECT_EQ("0.001", format("{:.3f}", 0.0005));
|
||||||
|
EXPECT_EQ("0.001", format("{:.3f}", 0.00149));
|
||||||
|
EXPECT_EQ("0.002", format("{:.3f}", 0.0015));
|
||||||
|
EXPECT_EQ("0.00123", format("{:.3}", 0.00123));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatNaN) {
|
TEST(FormatterTest, FormatNaN) {
|
||||||
|
Loading…
Reference in New Issue
Block a user