mirror of
https://github.com/fmtlib/fmt.git
synced 2025-01-08 13:40:15 +00:00
Optimize floating point formatting
This commit is contained in:
parent
f6d75c534c
commit
3c13a88b14
@ -2173,11 +2173,8 @@ FMT_SAFEBUFFERS decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|||||||
const carrier_uint significand_mask =
|
const carrier_uint significand_mask =
|
||||||
(static_cast<carrier_uint>(1) << float_info<T>::significand_bits) - 1;
|
(static_cast<carrier_uint>(1) << float_info<T>::significand_bits) - 1;
|
||||||
carrier_uint significand = (br & significand_mask);
|
carrier_uint significand = (br & significand_mask);
|
||||||
const carrier_uint exponent_mask =
|
|
||||||
((static_cast<carrier_uint>(1) << float_info<T>::exponent_bits) - 1)
|
|
||||||
<< float_info<T>::significand_bits;
|
|
||||||
int exponent =
|
int exponent =
|
||||||
static_cast<int>((br & exponent_mask) >> float_info<T>::significand_bits);
|
static_cast<int>((br & exponent_mask<T>()) >> float_info<T>::significand_bits);
|
||||||
|
|
||||||
if (exponent != 0) { // Check if normal.
|
if (exponent != 0) { // Check if normal.
|
||||||
exponent += float_info<T>::exponent_bias - float_info<T>::significand_bits;
|
exponent += float_info<T>::exponent_bias - float_info<T>::significand_bits;
|
||||||
|
@ -1269,6 +1269,13 @@ template <typename T> struct decimal_fp {
|
|||||||
template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT;
|
template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT;
|
||||||
} // namespace dragonbox
|
} // namespace dragonbox
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr typename dragonbox::float_info<T>::carrier_uint exponent_mask() {
|
||||||
|
using uint = typename dragonbox::float_info<T>::carrier_uint;
|
||||||
|
return ((uint(1) << dragonbox::float_info<T>::exponent_bits) - 1)
|
||||||
|
<< dragonbox::float_info<T>::significand_bits;
|
||||||
|
}
|
||||||
|
|
||||||
// A floating-point presentation format.
|
// A floating-point presentation format.
|
||||||
enum class float_format : unsigned char {
|
enum class float_format : unsigned char {
|
||||||
general, // General: exponent notation or fixed point based on magnitude.
|
general, // General: exponent notation or fixed point based on magnitude.
|
||||||
@ -1791,7 +1798,7 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp,
|
|||||||
Char decimal_point) {
|
Char decimal_point) {
|
||||||
auto significand = fp.significand;
|
auto significand = fp.significand;
|
||||||
int significand_size = get_significand_size(fp);
|
int significand_size = get_significand_size(fp);
|
||||||
const Char zero = static_cast<Char>('0');
|
static const Char zero = static_cast<Char>('0');
|
||||||
char sign = data::signs[fspecs.sign];
|
char sign = data::signs[fspecs.sign];
|
||||||
int size = significand_size + (fspecs.sign ? 1 : 0);
|
int size = significand_size + (fspecs.sign ? 1 : 0);
|
||||||
using iterator = remove_reference_t<decltype(reserve(out, 0))>;
|
using iterator = remove_reference_t<decltype(reserve(out, 0))>;
|
||||||
@ -1822,16 +1829,19 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp,
|
|||||||
|
|
||||||
size += (decimal_point ? 1 : 0) + num_zeros + 2 + exp_digits;
|
size += (decimal_point ? 1 : 0) + num_zeros + 2 + exp_digits;
|
||||||
char exp_char = fspecs.upper ? 'E' : 'e';
|
char exp_char = fspecs.upper ? 'E' : 'e';
|
||||||
return write_padded<align::right>(
|
auto write = [=](iterator it) {
|
||||||
out, specs, to_unsigned(size), [=](iterator it) mutable {
|
if (sign) *it++ = static_cast<Char>(sign);
|
||||||
if (sign) *it++ = static_cast<Char>(sign);
|
// Insert a decimal point after the first digit and add an exponent.
|
||||||
// Insert a decimal point after the first digit and add an exponent.
|
it = write_significand(it, significand, significand_size, 1,
|
||||||
it = write_significand(it, significand, significand_size, 1,
|
decimal_point);
|
||||||
decimal_point);
|
if (num_zeros > 0) it = std::fill_n(it, num_zeros, zero);
|
||||||
if (num_zeros > 0) it = std::fill_n(it, num_zeros, zero);
|
*it++ = static_cast<Char>(exp_char);
|
||||||
*it++ = static_cast<Char>(exp_char);
|
return write_exponent<Char>(output_exp, it);
|
||||||
return write_exponent<Char>(output_exp, it);
|
};
|
||||||
});
|
auto usize = to_unsigned(size);
|
||||||
|
return specs.width > 0
|
||||||
|
? write_padded<align::right>(out, specs, usize, write)
|
||||||
|
: base_iterator(out, write(reserve(out, usize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int exp = fp.exponent + significand_size;
|
int exp = fp.exponent + significand_size;
|
||||||
@ -1848,7 +1858,7 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp,
|
|||||||
if (num_zeros > 0) size += num_zeros;
|
if (num_zeros > 0) size += num_zeros;
|
||||||
}
|
}
|
||||||
return write_padded<align::right>(
|
return write_padded<align::right>(
|
||||||
out, specs, to_unsigned(size), [&](iterator it) mutable {
|
out, specs, to_unsigned(size), [&](iterator it) {
|
||||||
if (sign) *it++ = static_cast<Char>(sign);
|
if (sign) *it++ = static_cast<Char>(sign);
|
||||||
it = write_significand<Char>(it, significand, significand_size);
|
it = write_significand<Char>(it, significand, significand_size);
|
||||||
it = std::fill_n(it, fp.exponent, zero);
|
it = std::fill_n(it, fp.exponent, zero);
|
||||||
@ -1861,7 +1871,7 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp,
|
|||||||
int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
|
int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
|
||||||
size += 1 + (num_zeros > 0 ? num_zeros : 0);
|
size += 1 + (num_zeros > 0 ? num_zeros : 0);
|
||||||
return write_padded<align::right>(
|
return write_padded<align::right>(
|
||||||
out, specs, to_unsigned(size), [&](iterator it) mutable {
|
out, specs, to_unsigned(size), [&](iterator it) {
|
||||||
if (sign) *it++ = static_cast<Char>(sign);
|
if (sign) *it++ = static_cast<Char>(sign);
|
||||||
it = write_significand(it, significand, significand_size, exp,
|
it = write_significand(it, significand, significand_size, exp,
|
||||||
decimal_point);
|
decimal_point);
|
||||||
@ -1876,7 +1886,7 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp,
|
|||||||
}
|
}
|
||||||
size += 2 + num_zeros;
|
size += 2 + num_zeros;
|
||||||
return write_padded<align::right>(
|
return write_padded<align::right>(
|
||||||
out, specs, to_unsigned(size), [&](iterator it) mutable {
|
out, specs, to_unsigned(size), [&](iterator it) {
|
||||||
if (sign) *it++ = static_cast<Char>(sign);
|
if (sign) *it++ = static_cast<Char>(sign);
|
||||||
*it++ = zero;
|
*it++ = zero;
|
||||||
if (num_zeros == 0 && significand_size == 0 && !fspecs.showpoint)
|
if (num_zeros == 0 && significand_size == 0 && !fspecs.showpoint)
|
||||||
@ -1939,17 +1949,23 @@ template <typename Char, typename OutputIt, typename T,
|
|||||||
FMT_ENABLE_IF(is_fast_float<T>::value)>
|
FMT_ENABLE_IF(is_fast_float<T>::value)>
|
||||||
OutputIt write(OutputIt out, T value) {
|
OutputIt write(OutputIt out, T value) {
|
||||||
if (const_check(!is_supported_floating_point(value))) return out;
|
if (const_check(!is_supported_floating_point(value))) return out;
|
||||||
|
|
||||||
|
using type = conditional_t<std::is_same<T, long double>::value, double, T>;
|
||||||
|
using uint = typename dragonbox::float_info<type>::carrier_uint;
|
||||||
|
auto bits = bit_cast<uint>(value);
|
||||||
|
|
||||||
auto fspecs = float_specs();
|
auto fspecs = float_specs();
|
||||||
if (std::signbit(value)) { // value < 0 is false for NaN so use signbit.
|
auto sign_bit = bits & (uint(1) << (num_bits<uint>() - 1));
|
||||||
|
if (sign_bit != 0) {
|
||||||
fspecs.sign = sign::minus;
|
fspecs.sign = sign::minus;
|
||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto specs = basic_format_specs<Char>();
|
static const auto specs = basic_format_specs<Char>();
|
||||||
if (!std::isfinite(value))
|
uint mask = exponent_mask<type>();
|
||||||
|
if ((bits & mask) == mask)
|
||||||
return write_nonfinite(out, std::isinf(value), specs, fspecs);
|
return write_nonfinite(out, std::isinf(value), specs, fspecs);
|
||||||
|
|
||||||
using type = conditional_t<std::is_same<T, long double>::value, double, T>;
|
|
||||||
auto dec = dragonbox::to_decimal(static_cast<type>(value));
|
auto dec = dragonbox::to_decimal(static_cast<type>(value));
|
||||||
return write_float(out, dec, specs, fspecs, static_cast<Char>('.'));
|
return write_float(out, dec, specs, fspecs, static_cast<Char>('.'));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user