Add initial __float128 support

This commit is contained in:
Victor Zverovich 2022-03-14 17:00:21 -07:00
parent b6b003b073
commit a204b8dde7
2 changed files with 47 additions and 23 deletions

View File

@ -2164,31 +2164,34 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& fp,
} }
} }
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> #ifdef __SIZEOF_FLOAT128__
FMT_CONSTEXPR20 bool isinf(T value) { using float128 = __float128;
if (is_constant_evaluated()) { #else
#if defined(__cpp_if_constexpr) using float128 = void;
if constexpr (std::numeric_limits<double>::is_iec559) {
auto bits = bit_cast<uint64_t>(static_cast<double>(value));
return (bits & exponent_mask<double>()) &&
!(bits & ((uint64_t(1) << num_significand_bits<double>()) - 1));
}
#endif #endif
} template <typename T> using is_float128 = std::is_same<T, float128>;
return std::isinf(value);
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value &&
!is_float128<T>::value)>
FMT_CONSTEXPR20 bool isfinite(T value) {
if (is_constant_evaluated()) return value - value == 0;
return std::isfinite(value);
}
template <typename T, FMT_ENABLE_IF(is_float128<T>::value)>
constexpr bool isfinite(T value) {
return value - value == 0; // std::isfinite doesn't support __float128.
} }
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value &&
FMT_CONSTEXPR20 bool isfinite(T value) { !is_float128<T>::value)>
if (is_constant_evaluated()) { FMT_CONSTEXPR20 bool isinf(T value) {
#if defined(__cpp_if_constexpr) if (is_constant_evaluated()) return !isfinite(value) && value == value;
if constexpr (std::numeric_limits<double>::is_iec559) { return std::isinf(value);
auto bits = detail::bit_cast<uint64_t>(static_cast<double>(value)); }
return (bits & exponent_mask<double>()) != exponent_mask<double>(); template <typename T, FMT_ENABLE_IF(is_float128<T>::value)>
} constexpr bool isinf(T value) {
#endif // std::isinf doesn't support __float128.
} return !isfinite(value) && value == value;
return std::isfinite(value);
} }
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
@ -2201,7 +2204,7 @@ FMT_INLINE FMT_CONSTEXPR bool signbit(T value) {
} }
#endif #endif
} }
return std::signbit(value); return std::signbit(static_cast<double>(value));
} }
template <typename Char, typename OutputIt, typename T, template <typename Char, typename OutputIt, typename T,

View File

@ -66,6 +66,27 @@ TEST(uint128_test, minus) {
EXPECT_EQ(n - 2, 40); EXPECT_EQ(n - 2, 40);
} }
template <typename Float> void check_isfinite() {
using fmt::detail::isfinite;
EXPECT_TRUE(isfinite(Float(0.0)));
EXPECT_TRUE(isfinite(Float(42.0)));
EXPECT_TRUE(isfinite(Float(-42.0)));
EXPECT_TRUE(isfinite(Float(fmt::detail::max_value<double>())));
// Use double because std::numeric_limits is broken for __float128.
using limits = std::numeric_limits<double>;
EXPECT_FALSE(isfinite(Float(limits::infinity())));
EXPECT_FALSE(isfinite(Float(-limits::infinity())));
EXPECT_FALSE(isfinite(Float(limits::quiet_NaN())));
EXPECT_FALSE(isfinite(Float(-limits::quiet_NaN())));
}
TEST(float_test, isfinite) {
check_isfinite<double>();
#ifdef __SIZEOF_FLOAT128__
check_isfinite<fmt::detail::float128>();
#endif
}
struct uint32_pair { struct uint32_pair {
uint32_t u[2]; uint32_t u[2];
}; };