Add partial support for extended precision FP

This commit is contained in:
Victor Zverovich
2022-02-07 06:44:42 -08:00
parent 0a24a0714e
commit 2b6f7fc7a3
2 changed files with 38 additions and 23 deletions

View File

@@ -1198,7 +1198,7 @@ class utf8_to_utf16 {
namespace dragonbox {
// Type-specific information that Dragonbox uses.
template <class T> struct float_info;
template <typename T, typename Enable = void> struct float_info;
template <> struct float_info<float> {
using carrier_uint = uint32_t;
@@ -1246,6 +1246,15 @@ template <> struct float_info<double> {
static const int max_trailing_zeros = 16;
};
// 80-bit extended precision long double.
template <typename T>
struct float_info<T, enable_if_t<std::is_same<T, long double>::value &&
std::numeric_limits<T>::digits == 64>> {
using carrier_uint = detail::uint128_t;
static const int significand_bits = 64;
static const int exponent_bits = 15;
};
template <typename T> struct decimal_fp {
using significand_type = typename float_info<T>::carrier_uint;
significand_type significand;
@@ -1295,11 +1304,14 @@ template <typename T>
auto snprintf_float(T value, int precision, float_specs specs,
buffer<char>& buf) -> int;
template <typename T> constexpr auto promote_float(T value) -> T {
return value;
}
constexpr auto promote_float(float value) -> double {
return static_cast<double>(value);
template <typename T>
using convert_float_result =
conditional_t<std::is_same<T, float>::value || sizeof(T) == sizeof(double),
double, T>;
template <typename T>
constexpr auto convert_float(T value) -> convert_float_result<T> {
return static_cast<convert_float_result<T>>(value);
}
template <typename OutputIt, typename Char>
@@ -2207,7 +2219,7 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value,
memory_buffer buffer;
if (fspecs.format == float_format::hex) {
if (fspecs.sign) buffer.push_back(detail::sign<char>(fspecs.sign));
snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
snprintf_float(convert_float(value), specs.precision, fspecs, buffer);
return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
specs);
}
@@ -2222,7 +2234,7 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value,
}
if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
if (!is_fast_float<T>()) fspecs.fallback = true;
int exp = format_float(promote_float(value), precision, fspecs, buffer);
int exp = format_float(convert_float(value), precision, fspecs, buffer);
fspecs.precision = precision;
auto fp = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
return write_float(out, fp, specs, fspecs, loc);