mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 11:17:35 +02:00
Test get_round_direction
This commit is contained in:
@ -445,6 +445,28 @@ FMT_FUNC fp get_cached_power(int min_exponent, int& pow10_exponent) {
|
|||||||
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum round_direction { unknown, up, down };
|
||||||
|
|
||||||
|
// Given the divisor (normally a power of 10), the remainder = v % divisor for
|
||||||
|
// some number v and the error, returns whether v should be rounded up, down, or
|
||||||
|
// whether the rounding direction can't be determined due to error.
|
||||||
|
// error should be less than divisor / 2.
|
||||||
|
inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder,
|
||||||
|
uint64_t error) {
|
||||||
|
FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow.
|
||||||
|
FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow.
|
||||||
|
FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow.
|
||||||
|
// Round down if (remainder + error) * 2 <= divisor.
|
||||||
|
if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2)
|
||||||
|
return down;
|
||||||
|
// Round up if (remainder - error) * 2 >= divisor.
|
||||||
|
if (remainder >= error &&
|
||||||
|
remainder - error >= divisor - (remainder - error)) {
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
return unknown;
|
||||||
|
}
|
||||||
|
|
||||||
// Generates output using Grisu2 digit-gen algorithm.
|
// Generates output using Grisu2 digit-gen algorithm.
|
||||||
template <typename Stop>
|
template <typename Stop>
|
||||||
int grisu2_gen_digits(char* buf, fp value, uint64_t error_ulp, int& exp,
|
int grisu2_gen_digits(char* buf, fp value, uint64_t error_ulp, int& exp,
|
||||||
@ -544,29 +566,13 @@ struct fixed_stop {
|
|||||||
return full_exp <= 0 && -full_exp >= precision;
|
return full_exp <= 0 && -full_exp >= precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum round_direction { unknown, up, down };
|
|
||||||
|
|
||||||
static round_direction round(uint64_t remainder, uint64_t divisor,
|
|
||||||
uint64_t error) {
|
|
||||||
assert(error < divisor && error < divisor - error);
|
|
||||||
// Round down if (remainder + error) * 2 <= divisor.
|
|
||||||
if (remainder < divisor - remainder && error * 2 <= divisor - remainder * 2)
|
|
||||||
return down;
|
|
||||||
// Round up if (remainder - error) * 2 >= divisor.
|
|
||||||
if (remainder >= error &&
|
|
||||||
remainder - error >= divisor - (remainder - error)) {
|
|
||||||
return up;
|
|
||||||
}
|
|
||||||
return unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
bool init(char* buf, int& size, uint64_t remainder, uint64_t divisor,
|
||||||
uint64_t error, int& exp) {
|
uint64_t error, int& exp) {
|
||||||
if (!fixed) return false;
|
if (!fixed) return false;
|
||||||
int full_exp = exp + exp10;
|
int full_exp = exp + exp10;
|
||||||
if (full_exp >= 0) precision += full_exp;
|
if (full_exp >= 0) precision += full_exp;
|
||||||
if (!enough_precision(full_exp)) return false;
|
if (!enough_precision(full_exp)) return false;
|
||||||
switch (round(remainder, divisor, error)) {
|
switch (get_round_direction(divisor, remainder, error)) {
|
||||||
case unknown:
|
case unknown:
|
||||||
size = -1;
|
size = -1;
|
||||||
break;
|
break;
|
||||||
@ -595,7 +601,7 @@ struct fixed_stop {
|
|||||||
} else {
|
} else {
|
||||||
assert(error == 1 && divisor > 2);
|
assert(error == 1 && divisor > 2);
|
||||||
}
|
}
|
||||||
switch (round(remainder, divisor, error)) {
|
switch (get_round_direction(divisor, remainder, error)) {
|
||||||
case unknown:
|
case unknown:
|
||||||
size = -1;
|
size = -1;
|
||||||
break;
|
break;
|
||||||
@ -696,8 +702,8 @@ void sprintf_format(Double value, internal::buffer& buf,
|
|||||||
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
||||||
|
|
||||||
// Build format string.
|
// Build format string.
|
||||||
enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg
|
enum { max_format_size = 10 }; // longest format: %#-*.*Lg
|
||||||
char format[MAX_FORMAT_SIZE];
|
char format[max_format_size];
|
||||||
char* format_ptr = format;
|
char* format_ptr = format;
|
||||||
*format_ptr++ = '%';
|
*format_ptr++ = '%';
|
||||||
if (spec.has(HASH_FLAG) || !spec.type) *format_ptr++ = '#';
|
if (spec.has(HASH_FLAG) || !spec.type) *format_ptr++ = '#';
|
||||||
|
@ -98,6 +98,29 @@ TEST(FPTest, GetCachedPower) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FPTest, GetRoundDirection) {
|
||||||
|
using fmt::internal::get_round_direction;
|
||||||
|
EXPECT_EQ(fmt::internal::down, get_round_direction(100, 50, 0));
|
||||||
|
EXPECT_EQ(fmt::internal::up, get_round_direction(100, 51, 0));
|
||||||
|
EXPECT_EQ(fmt::internal::down, get_round_direction(100, 40, 10));
|
||||||
|
EXPECT_EQ(fmt::internal::up, get_round_direction(100, 60, 10));
|
||||||
|
for (int i = 41; i < 60; ++i)
|
||||||
|
EXPECT_EQ(fmt::internal::unknown, get_round_direction(100, i, 10));
|
||||||
|
uint64_t max = std::numeric_limits<uint64_t>::max();
|
||||||
|
EXPECT_THROW(get_round_direction(100, 100, 0), assertion_failure);
|
||||||
|
EXPECT_THROW(get_round_direction(100, 0, 100), assertion_failure);
|
||||||
|
EXPECT_THROW(get_round_direction(100, 0, 50), assertion_failure);
|
||||||
|
// Check that remainder + error doesn't overflow.
|
||||||
|
EXPECT_EQ(fmt::internal::up, get_round_direction(max, max - 1, 2));
|
||||||
|
// Check that 2 * (remainder + error) doesn't overflow.
|
||||||
|
EXPECT_EQ(fmt::internal::unknown,
|
||||||
|
get_round_direction(max, max / 2 + 1, max / 2));
|
||||||
|
// Check that remainder - error doesn't overflow.
|
||||||
|
EXPECT_EQ(fmt::internal::unknown, get_round_direction(100, 40, 41));
|
||||||
|
// Check that 2 * (remainder - error) doesn't overflow.
|
||||||
|
EXPECT_EQ(fmt::internal::up, get_round_direction(max, max - 1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
||||||
fmt::memory_buffer buf;
|
fmt::memory_buffer buf;
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
|
Reference in New Issue
Block a user