mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Use grisu for fixed precision
This commit is contained in:
@ -534,8 +534,14 @@ int grisu2_gen_digits(char* buf, fp value, uint64_t error_ulp, int& exp,
|
|||||||
struct fixed_stop {
|
struct fixed_stop {
|
||||||
int precision;
|
int precision;
|
||||||
int exp10;
|
int exp10;
|
||||||
|
bool fixed;
|
||||||
|
|
||||||
void on_exp(int exp) { precision += exp + exp10; }
|
void on_exp(int exp) {
|
||||||
|
if (!fixed) return;
|
||||||
|
exp += exp10;
|
||||||
|
if (exp >= 0)
|
||||||
|
precision += exp;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator()(char*, int& size, uint64_t remainder, uint64_t divisor,
|
bool operator()(char*, int& size, uint64_t remainder, uint64_t divisor,
|
||||||
uint64_t error, int&, bool integral) {
|
uint64_t error, int&, bool integral) {
|
||||||
@ -549,8 +555,9 @@ struct fixed_stop {
|
|||||||
size = -1;
|
size = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
assert(error == 1 && divisor > 2);
|
assert(error == 1 && divisor > 2);
|
||||||
|
}
|
||||||
// Round down if (remainder + error) * 2 <= divisor.
|
// Round down if (remainder + error) * 2 <= divisor.
|
||||||
if (remainder < divisor - remainder && error * 2 <= divisor - remainder * 2)
|
if (remainder < divisor - remainder && error * 2 <= divisor - remainder * 2)
|
||||||
return true;
|
return true;
|
||||||
@ -582,7 +589,7 @@ struct shortest_stop {
|
|||||||
|
|
||||||
template <typename Double>
|
template <typename Double>
|
||||||
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
||||||
grisu2_format(Double value, buffer& buf, int precision, int& exp) {
|
grisu2_format(Double value, buffer& buf, int precision, bool fixed, int& exp) {
|
||||||
FMT_ASSERT(value >= 0, "value is negative");
|
FMT_ASSERT(value >= 0, "value is negative");
|
||||||
if (value <= 0) { // <= instead of == to silence a warning.
|
if (value <= 0) { // <= instead of == to silence a warning.
|
||||||
if (precision < 0) {
|
if (precision < 0) {
|
||||||
@ -606,7 +613,7 @@ grisu2_format(Double value, buffer& buf, int precision, int& exp) {
|
|||||||
min_exp - (fp_value.e + fp::significand_size), cached_exp10);
|
min_exp - (fp_value.e + fp::significand_size), cached_exp10);
|
||||||
fp_value = fp_value * cached_pow;
|
fp_value = fp_value * cached_pow;
|
||||||
int size = grisu2_gen_digits(buf.data(), fp_value, 1, exp,
|
int size = grisu2_gen_digits(buf.data(), fp_value, 1, exp,
|
||||||
fixed_stop{precision, -cached_exp10});
|
fixed_stop{precision, -cached_exp10, fixed});
|
||||||
if (size < 0) return false;
|
if (size < 0) return false;
|
||||||
buf.resize(to_unsigned(size));
|
buf.resize(to_unsigned(size));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1139,10 +1139,10 @@ namespace internal {
|
|||||||
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
|
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
|
||||||
template <typename Double>
|
template <typename Double>
|
||||||
FMT_API typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
FMT_API typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
||||||
grisu2_format(Double value, buffer& buf, int precision, int& exp);
|
grisu2_format(Double value, buffer& buf, int precision, bool fixed, int& exp);
|
||||||
template <typename Double>
|
template <typename Double>
|
||||||
inline typename std::enable_if<sizeof(Double) != sizeof(uint64_t), bool>::type
|
inline typename std::enable_if<sizeof(Double) != sizeof(uint64_t), bool>::type
|
||||||
grisu2_format(Double, buffer&, int, int&) {
|
grisu2_format(Double, buffer&, int, bool, int&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2866,9 +2866,9 @@ 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 || handler.fixed) && !spec.has_precision() &&
|
(!spec.type || handler.fixed) &&
|
||||||
internal::grisu2_format(static_cast<double>(value), buffer,
|
internal::grisu2_format(static_cast<double>(value), buffer,
|
||||||
precision, exp);
|
precision, handler.fixed, exp);
|
||||||
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
||||||
align_spec as = spec;
|
align_spec as = spec;
|
||||||
if (spec.align() == ALIGN_NUMERIC) {
|
if (spec.align() == ALIGN_NUMERIC) {
|
||||||
|
@ -11,7 +11,7 @@ FMT_BEGIN_NAMESPACE
|
|||||||
template struct internal::basic_data<void>;
|
template struct internal::basic_data<void>;
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of grisu2_format.
|
// Workaround a bug in MSVC2013 that prevents instantiation of grisu2_format.
|
||||||
bool (*instantiate_grisu2_format)(double, internal::buffer&, int,
|
bool (*instantiate_grisu2_format)(double, internal::buffer&, int, bool,
|
||||||
int&) = internal::grisu2_format;
|
int&) = internal::grisu2_format;
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
@ -103,7 +103,7 @@ TEST(FPTest, GetCachedPower) {
|
|||||||
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
||||||
fmt::memory_buffer buf;
|
fmt::memory_buffer buf;
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
grisu2_format(4.2f, buf, -1, exp);
|
grisu2_format(4.2f, buf, -1, false, exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> struct ValueExtractor : fmt::internal::function<T> {
|
template <typename T> struct ValueExtractor : fmt::internal::function<T> {
|
||||||
|
Reference in New Issue
Block a user