// Copyright 2023 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_DECIMAL_decimal_fast64_t_HPP #define BOOST_DECIMAL_decimal_fast64_t_HPP #include #include #include #include #include #include "detail/int128.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_DECIMAL_BUILD_MODULE #include #include #endif namespace boost { namespace decimal { namespace detail { BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE auto d64_fast_inf {UINT64_C(0b1) << 61U}; BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE auto d64_fast_qnan {UINT64_C(0b11) << 61U}; BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE auto d64_fast_snan {UINT64_C(0b111) << 61U}; template constexpr auto to_chars_scientific_impl(char* first, char* last, const TargetDecimalType& value, chars_format fmt) noexcept -> to_chars_result; template constexpr auto to_chars_fixed_impl(char* first, char* last, const TargetDecimalType& value, chars_format fmt) noexcept -> to_chars_result; template constexpr auto to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result; template constexpr auto to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result; template constexpr auto d64_fma_impl(T x, T y, T z) noexcept -> T; template constexpr auto write_payload(typename TargetDecimalType::significand_type payload_value) BOOST_DECIMAL_REQUIRES(detail::is_fast_type_v, TargetDecimalType); } // namespace detail #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4324) // Structure was padded due to alignment specifier #endif BOOST_DECIMAL_EXPORT class alignas(8) decimal_fast64_t final { public: using significand_type = std::uint64_t; using exponent_type = std::uint16_t; using biased_exponent_type = std::int32_t; private: // In regular decimal64_t we have to decode the significand end exponent // Here we will store them directly to avoid the overhead of decoding significand_type significand_ {}; exponent_type exponent_ {}; bool sign_ {}; char pad_[5] {}; constexpr auto isneg() const noexcept -> bool { return sign_; } constexpr auto full_significand() const noexcept -> significand_type { return significand_; } constexpr auto unbiased_exponent() const noexcept -> exponent_type { return exponent_; } constexpr auto biased_exponent() const noexcept -> biased_exponent_type { return static_cast(exponent_) - detail::bias_v; } constexpr auto to_components() const noexcept -> detail::decimal_fast64_t_components { return {full_significand(), biased_exponent(), isneg()}; } // Equality template between any integer type and decimal32_t template friend constexpr auto mixed_equality_impl(Decimal lhs, Integer rhs) noexcept -> std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_integral_v), bool>; template friend constexpr auto mixed_decimal_equality_impl(Decimal1 lhs, Decimal2 rhs) noexcept -> std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_decimal_floating_point_v), bool>; // Template to compare operator< for any integer type and decimal32_t template friend constexpr auto less_impl(Decimal lhs, Integer rhs) noexcept -> std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_integral_v), bool>; template friend constexpr auto mixed_decimal_less_impl(Decimal1 lhs, Decimal2 rhs) noexcept -> std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_decimal_floating_point_v), bool>; template friend constexpr auto to_integral(Decimal val) noexcept BOOST_DECIMAL_REQUIRES_TWO_RETURN(detail::is_decimal_floating_point_v, Decimal, detail::is_integral_v, TargetType, TargetType); template friend BOOST_DECIMAL_CXX20_CONSTEXPR auto to_float(Decimal val) noexcept BOOST_DECIMAL_REQUIRES_TWO_RETURN(detail::is_decimal_floating_point_v, Decimal, detail::is_floating_point_v, TargetType, TargetType); template friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType; friend constexpr auto d64_fast_div_impl(const decimal_fast64_t& lhs, const decimal_fast64_t& rhs, decimal_fast64_t& q, decimal_fast64_t& r) noexcept -> void; template friend constexpr auto ilogb(T d) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, int); template friend constexpr auto logb(T num) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T); friend constexpr auto not_finite(decimal_fast64_t val) noexcept -> bool; template friend constexpr auto to_dpd_d64(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint64_t); template friend constexpr auto detail::add_impl(const T& lhs, const T& rhs) noexcept -> ReturnType; template friend constexpr auto detail::d64_mul_impl(const T& lhs, const T& rhs) noexcept -> ReturnType; template BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_equality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; template BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_inequality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; template BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_less_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; template BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_less_equal_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; template friend constexpr auto detail::nextafter_impl(DecimalType val, bool direction) noexcept -> DecimalType; template friend constexpr auto detail::to_chars_scientific_impl(char* first, char* last, const TargetDecimalType& value, chars_format fmt) noexcept -> to_chars_result; template friend constexpr auto detail::to_chars_fixed_impl(char* first, char* last, const TargetDecimalType& value, const chars_format fmt) noexcept -> to_chars_result; template friend constexpr auto detail::to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result; template friend constexpr auto detail::to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result; template friend constexpr auto detail::d64_fma_impl(T x, T y, T z) noexcept -> T; template friend constexpr auto detail::write_payload(typename TargetDecimalType::significand_type payload_value) BOOST_DECIMAL_REQUIRES(detail::is_fast_type_v, TargetDecimalType); template friend constexpr auto read_payload(T value) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_fast_type_v, T, typename T::significand_type); #if !defined(BOOST_DECIMAL_DISABLE_CLIB) constexpr decimal_fast64_t(const char* str, std::size_t len); #endif friend constexpr auto nan_conversion(const decimal_fast64_t value) noexcept -> decimal_fast64_t { constexpr auto convert_nan_mask {detail::d64_fast_qnan ^ detail::d64_fast_snan}; decimal_fast64_t return_value {value}; return_value.significand_ ^= convert_nan_mask; return return_value; } template friend constexpr Decimal detail::check_non_finite(Decimal lhs, Decimal rhs) noexcept; template friend constexpr Decimal detail::check_non_finite(Decimal x) noexcept; public: constexpr decimal_fast64_t() noexcept = default; #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template && detail::is_integral_v, bool> = true> #endif constexpr decimal_fast64_t(T1 coeff, T2 exp, detail::construction_sign_wrapper resultant_sign = construction_sign::positive) noexcept; #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template && detail::is_integral_v, bool> = true> #endif constexpr decimal_fast64_t(T1, T2, bool) noexcept { static_assert(detail::is_unsigned_v, "Construction from signed integer, exponent, and sign is ambiguous, so it is disallowed. You must use an Unsigned Integer for the coefficient to construct from {coefficient, exponent, sign}"); } #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template && detail::is_integral_v, bool> = true> #endif constexpr decimal_fast64_t(T1 coeff, T2 exp) noexcept; explicit constexpr decimal_fast64_t(bool value) noexcept; #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template , bool> = true> #endif #if !defined(BOOST_DECIMAL_ALLOW_IMPLICIT_CONVERSIONS) && !defined(BOOST_DECIMAL_ALLOW_IMPLICIT_INTEGER_CONVERSIONS) explicit #endif constexpr decimal_fast64_t(Integer val) noexcept; #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template , bool> = true> #endif #if !defined(BOOST_DECIMAL_ALLOW_IMPLICIT_CONVERSIONS) && !defined(BOOST_DECIMAL_ALLOW_IMPLICIT_FLOAT_CONVERSIONS) explicit #endif BOOST_DECIMAL_CXX20_CONSTEXPR decimal_fast64_t(Float val) noexcept; #ifdef BOOST_DECIMAL_UNSUPPORTED_LONG_DOUBLE explicit constexpr decimal_fast64_t(long double val) noexcept = delete; #endif friend constexpr auto direct_init_d64(decimal_fast64_t::significand_type significand, decimal_fast64_t::exponent_type exponent, bool sign) noexcept -> decimal_fast64_t; #if !defined(BOOST_DECIMAL_DISABLE_CLIB) explicit constexpr decimal_fast64_t(const char* str); #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW explicit inline decimal_fast64_t(const std::string& str); #else explicit constexpr decimal_fast64_t(std::string_view str); #endif #endif // BOOST_DECIMAL_DISABLE_CLIB // Classification functions friend constexpr auto signbit(decimal_fast64_t val) noexcept -> bool; friend constexpr auto isinf(decimal_fast64_t val) noexcept -> bool; friend constexpr auto isnan(decimal_fast64_t val) noexcept -> bool; friend constexpr auto issignaling(decimal_fast64_t val) noexcept -> bool; friend constexpr auto isnormal(decimal_fast64_t val) noexcept -> bool; friend constexpr auto isfinite(decimal_fast64_t val) noexcept -> bool; // Comparison operator friend constexpr auto operator==(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> bool; friend constexpr auto operator!=(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> bool; friend constexpr auto operator<(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> bool; friend constexpr auto operator<=(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> bool; friend constexpr auto operator>(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> bool; friend constexpr auto operator>=(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> bool; // Mixed type comparison operators template friend constexpr auto operator==(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator==(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator!=(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator!=(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator<(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator<(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator<=(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator<=(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator>(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator>(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator>=(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); template friend constexpr auto operator>=(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool); // C++20 Spaceship operator #ifdef BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR friend constexpr auto operator<=>(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> std::partial_ordering; template friend constexpr auto operator<=>(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering); template friend constexpr auto operator<=>(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering); #endif // Conversions explicit constexpr operator bool() const noexcept; explicit constexpr operator int() const noexcept; explicit constexpr operator unsigned() const noexcept; explicit constexpr operator long() const noexcept; explicit constexpr operator unsigned long() const noexcept; explicit constexpr operator long long() const noexcept; explicit constexpr operator unsigned long long() const noexcept; #ifdef BOOST_DECIMAL_HAS_INT128 explicit constexpr operator detail::builtin_int128_t() const noexcept; explicit constexpr operator detail::builtin_uint128_t() const noexcept; #endif explicit BOOST_DECIMAL_CXX20_CONSTEXPR operator float() const noexcept; explicit BOOST_DECIMAL_CXX20_CONSTEXPR operator double() const noexcept; #ifndef BOOST_DECIMAL_UNSUPPORTED_LONG_DOUBLE explicit BOOST_DECIMAL_CXX20_CONSTEXPR operator long double() const noexcept; #endif #ifdef BOOST_DECIMAL_HAS_FLOAT16 explicit constexpr operator std::float16_t() const noexcept; #endif #ifdef BOOST_DECIMAL_HAS_FLOAT32 explicit constexpr operator std::float32_t() const noexcept; #endif #ifdef BOOST_DECIMAL_HAS_FLOAT64 explicit constexpr operator std::float64_t() const noexcept; #endif #ifdef BOOST_DECIMAL_HAS_BRAINFLOAT16 explicit constexpr operator std::bfloat16_t() const noexcept; #endif // Conversion to other decimal type template && (detail::decimal_val_v > detail::decimal_val_v), bool> = true> constexpr operator Decimal() const noexcept; template && (detail::decimal_val_v <= detail::decimal_val_v), bool> = true> explicit constexpr operator Decimal() const noexcept; // Unary Operators friend constexpr auto operator+(decimal_fast64_t val) noexcept -> decimal_fast64_t; friend constexpr auto operator-(decimal_fast64_t val) noexcept -> decimal_fast64_t; // Basic arithmetic operators friend constexpr auto operator+(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> decimal_fast64_t; friend constexpr auto operator-(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> decimal_fast64_t; friend constexpr auto operator*(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> decimal_fast64_t; friend constexpr auto operator/(const decimal_fast64_t& lhs, const decimal_fast64_t& rhs) noexcept -> decimal_fast64_t; friend constexpr auto operator%(decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> decimal_fast64_t; // Mixed type arithmetic operators template friend constexpr auto operator+(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator+(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator-(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator-(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator*(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator*(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator/(decimal_fast64_t lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); template friend constexpr auto operator/(Integer lhs, decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t); // Compound Operators constexpr auto operator+=(decimal_fast64_t rhs) noexcept -> decimal_fast64_t&; constexpr auto operator-=(decimal_fast64_t rhs) noexcept -> decimal_fast64_t&; constexpr auto operator*=(decimal_fast64_t rhs) noexcept -> decimal_fast64_t&; constexpr auto operator/=(decimal_fast64_t rhs) noexcept -> decimal_fast64_t&; // Mixed type compound operators template constexpr auto operator+=(Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&); template constexpr auto operator-=(Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&); template constexpr auto operator*=(Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&); template constexpr auto operator/=(Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&); // Increment and decrement constexpr auto operator++() noexcept -> decimal_fast64_t&; constexpr auto operator++(int) noexcept -> decimal_fast64_t; constexpr auto operator--() noexcept -> decimal_fast64_t&; constexpr auto operator--(int) noexcept -> decimal_fast64_t; // Cmath friend functions template friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type; friend constexpr auto copysignd64f(decimal_fast64_t mag, decimal_fast64_t sgn) noexcept -> decimal_fast64_t; friend constexpr auto scalbnd64f(decimal_fast64_t num, int exp) noexcept -> decimal_fast64_t; friend constexpr auto scalblnd64f(decimal_fast64_t num, long exp) noexcept -> decimal_fast64_t; friend constexpr auto quantexpd64f(decimal_fast64_t x) noexcept -> int; }; #ifdef _MSC_VER # pragma warning(pop) #endif #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template && detail::is_integral_v, bool>> #endif constexpr decimal_fast64_t::decimal_fast64_t(T1 coeff, T2 exp, const detail::construction_sign_wrapper resultant_sign) noexcept { using minimum_coefficient_size = std::conditional_t<(sizeof(T1) > sizeof(significand_type)), T1, significand_type>; minimum_coefficient_size min_coeff {coeff}; const auto is_negative {static_cast(resultant_sign)}; sign_ = is_negative; // Normalize the value, so we don't have to worry about it with operations detail::normalize(min_coeff, exp, is_negative); significand_ = static_cast(min_coeff); const auto biased_exp {significand_ == 0U ? 0 : exp + detail::bias_v}; if (biased_exp > detail::max_biased_exp_v) { significand_ = detail::d64_fast_inf; } else if (biased_exp >= 0) { exponent_ = static_cast(biased_exp); } else { // Flush denorms to zero significand_ = static_cast(0); exponent_ = static_cast(detail::bias_v); sign_ = false; } } #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template && detail::is_integral_v, bool>> #endif constexpr decimal_fast64_t::decimal_fast64_t(const T1 coeff, const T2 exp) noexcept : decimal_fast64_t(detail::make_positive_unsigned(coeff), exp, coeff < 0) {} constexpr decimal_fast64_t::decimal_fast64_t(const bool value) noexcept : decimal_fast64_t(static_cast(value), 0, false) {} #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template , bool>> #endif constexpr decimal_fast64_t::decimal_fast64_t(const Integer val) noexcept : decimal_fast64_t{val, 0} {} #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wfloat-equal" #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wfloat-equal" #endif #ifdef BOOST_DECIMAL_HAS_CONCEPTS template #else template , bool>> #endif BOOST_DECIMAL_CXX20_CONSTEXPR decimal_fast64_t::decimal_fast64_t(const Float val) noexcept { #ifndef BOOST_DECIMAL_FAST_MATH if (val != val) { significand_ = detail::d64_fast_qnan; } else if (val == std::numeric_limits::infinity() || val == -std::numeric_limits::infinity()) { significand_ = detail::d64_fast_inf; } else #endif { const auto components {detail::ryu::floating_point_to_fd128(val)}; *this = decimal_fast64_t {components.mantissa, components.exponent, components.sign}; } } #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #endif constexpr auto direct_init_d64(const decimal_fast64_t::significand_type significand, const decimal_fast64_t::exponent_type exponent, const bool sign) noexcept -> decimal_fast64_t { decimal_fast64_t val {}; val.significand_ = significand; val.exponent_ = exponent; val.sign_ = sign; return val; } namespace detail { template class numeric_limits_impl64f { public: static constexpr bool is_specialized = true; static constexpr bool is_signed = true; static constexpr bool is_integer = false; static constexpr bool is_exact = false; static constexpr bool has_infinity = true; static constexpr bool has_quiet_NaN = true; static constexpr bool has_signaling_NaN = true; // These members were deprecated in C++23 #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) static constexpr std::float_denorm_style has_denorm = std::denorm_present; static constexpr bool has_denorm_loss = true; #endif static constexpr std::float_round_style round_style = std::round_indeterminate; static constexpr bool is_iec559 = false; static constexpr bool is_bounded = true; static constexpr bool is_modulo = false; static constexpr int digits = 16; static constexpr int digits10 = digits; static constexpr int max_digits10 = digits; static constexpr int radix = 10; static constexpr int min_exponent = -383; static constexpr int min_exponent10 = min_exponent; static constexpr int max_exponent = 384; static constexpr int max_exponent10 = max_exponent; static constexpr bool traps = std::numeric_limits::traps; static constexpr bool tinyness_before = true; // Member functions static constexpr auto (min) () -> boost::decimal::decimal_fast64_t { return {UINT32_C(1), min_exponent}; } static constexpr auto (max) () -> boost::decimal::decimal_fast64_t { return {UINT64_C(9'999'999'999'999'999), max_exponent - digits + 1}; } static constexpr auto lowest () -> boost::decimal::decimal_fast64_t { return {UINT64_C(9'999'999'999'999'999), max_exponent - digits + 1, construction_sign::negative}; } static constexpr auto epsilon () -> boost::decimal::decimal_fast64_t { return {UINT32_C(1), -digits + 1}; } static constexpr auto round_error () -> boost::decimal::decimal_fast64_t { return epsilon(); } static constexpr auto infinity () -> boost::decimal::decimal_fast64_t { return boost::decimal::direct_init_d64( boost::decimal::detail::d64_fast_inf, 0, false); } static constexpr auto quiet_NaN () -> boost::decimal::decimal_fast64_t { return boost::decimal::direct_init_d64( boost::decimal::detail::d64_fast_qnan, 0, false); } static constexpr auto signaling_NaN() -> boost::decimal::decimal_fast64_t { return boost::decimal::direct_init_d64( boost::decimal::detail::d64_fast_snan, 0, false); } static constexpr auto denorm_min () -> boost::decimal::decimal_fast64_t { return min(); } }; #if !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L template constexpr bool numeric_limits_impl64f::is_specialized; template constexpr bool numeric_limits_impl64f::is_signed; template constexpr bool numeric_limits_impl64f::is_integer; template constexpr bool numeric_limits_impl64f::is_exact; template constexpr bool numeric_limits_impl64f::has_infinity; template constexpr bool numeric_limits_impl64f::has_quiet_NaN; template constexpr bool numeric_limits_impl64f::has_signaling_NaN; // These members were deprecated in C++23 #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) template constexpr std::float_denorm_style numeric_limits_impl64f::has_denorm; template constexpr bool numeric_limits_impl64f::has_denorm_loss; #endif template constexpr std::float_round_style numeric_limits_impl64f::round_style; template constexpr bool numeric_limits_impl64f::is_iec559; template constexpr bool numeric_limits_impl64f::is_bounded; template constexpr bool numeric_limits_impl64f::is_modulo; template constexpr int numeric_limits_impl64f::digits; template constexpr int numeric_limits_impl64f::digits10; template constexpr int numeric_limits_impl64f::max_digits10; template constexpr int numeric_limits_impl64f::radix; template constexpr int numeric_limits_impl64f::min_exponent; template constexpr int numeric_limits_impl64f::min_exponent10; template constexpr int numeric_limits_impl64f::max_exponent; template constexpr int numeric_limits_impl64f::max_exponent10; template constexpr bool numeric_limits_impl64f::traps; template constexpr bool numeric_limits_impl64f::tinyness_before; #endif // !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L } // namespace detail } // namespace decimal } // namespace boost namespace std { #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wmismatched-tags" #endif template <> class numeric_limits : public boost::decimal::detail::numeric_limits_impl64f {}; #ifdef __clang__ # pragma clang diagnostic pop #endif } // namespace std namespace boost { namespace decimal { constexpr auto signbit(const decimal_fast64_t val) noexcept -> bool { return val.sign_; } constexpr auto isinf(const decimal_fast64_t val) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ == detail::d64_fast_inf; #else static_cast(val); return false; #endif } constexpr auto isnan(const decimal_fast64_t val) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ >= detail::d64_fast_qnan; #else static_cast(val); return false; #endif } constexpr auto issignaling(const decimal_fast64_t val) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH return val.significand_ >= detail::d64_fast_snan; #else static_cast(val); return false; #endif } constexpr auto isnormal(const decimal_fast64_t val) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH if (val.exponent_ <= static_cast(detail::precision_v - 1)) { return false; } return (val.significand_ != 0) && isfinite(val); #else return val.significand_ != 0; #endif } constexpr auto isfinite(const decimal_fast64_t val) noexcept -> bool { return val.significand_ < detail::d64_fast_inf; } BOOST_DECIMAL_FORCE_INLINE constexpr auto not_finite(const decimal_fast64_t val) noexcept -> bool { return val.significand_ >= detail::d64_fast_inf; } constexpr auto operator==(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> bool { return fast_equality_impl(lhs, rhs); } template constexpr auto operator==(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return mixed_equality_impl(lhs, rhs); } template constexpr auto operator==(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return mixed_equality_impl(rhs, lhs); } constexpr auto operator!=(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> bool { return fast_inequality_impl(lhs, rhs); } template constexpr auto operator!=(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return !(lhs == rhs); } template constexpr auto operator!=(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return !(lhs == rhs); } constexpr auto operator<(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> bool { return fast_less_impl(lhs, rhs); } template constexpr auto operator<(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return less_impl(lhs, rhs); } template constexpr auto operator<(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(rhs)) { return false; } #endif return !less_impl(rhs, lhs) && lhs != rhs; } constexpr auto operator<=(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } #endif return !(rhs < lhs); } template constexpr auto operator<=(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs)) { return false; } #endif return !(rhs < lhs); } template constexpr auto operator<=(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(rhs)) { return false; } #endif return !(rhs < lhs); } constexpr auto operator>(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> bool { return rhs < lhs; } template constexpr auto operator>(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return rhs < lhs; } template constexpr auto operator>(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { return rhs < lhs; } constexpr auto operator>=(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isnan(rhs)) { return false; } #endif return !(lhs < rhs); } template constexpr auto operator>=(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs)) { return false; } #endif return !(lhs < rhs); } template constexpr auto operator>=(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, bool) { #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(rhs)) { return false; } #endif return !(lhs < rhs); } #ifdef BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR constexpr auto operator<=>(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> std::partial_ordering { if (lhs < rhs) { return std::partial_ordering::less; } else if (lhs > rhs) { return std::partial_ordering::greater; } else if (lhs == rhs) { return std::partial_ordering::equivalent; } return std::partial_ordering::unordered; } template constexpr auto operator<=>(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering) { if (lhs < rhs) { return std::partial_ordering::less; } else if (lhs > rhs) { return std::partial_ordering::greater; } else if (lhs == rhs) { return std::partial_ordering::equivalent; } return std::partial_ordering::unordered; } template constexpr auto operator<=>(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering) { if (lhs < rhs) { return std::partial_ordering::less; } else if (lhs > rhs) { return std::partial_ordering::greater; } else if (lhs == rhs) { return std::partial_ordering::equivalent; } return std::partial_ordering::unordered; } #endif // BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR constexpr auto operator+(const decimal_fast64_t val) noexcept -> decimal_fast64_t { return val; } constexpr auto operator-(decimal_fast64_t val) noexcept -> decimal_fast64_t { val.sign_ = !val.sign_; return val; } constexpr decimal_fast64_t::operator bool() const noexcept { constexpr decimal_fast64_t zero {0, 0}; return *this != zero; } constexpr decimal_fast64_t::operator int() const noexcept { return to_integral(*this); } constexpr decimal_fast64_t::operator unsigned() const noexcept { return to_integral(*this); } constexpr decimal_fast64_t::operator long() const noexcept { return to_integral(*this); } constexpr decimal_fast64_t::operator unsigned long() const noexcept { return to_integral(*this); } constexpr decimal_fast64_t::operator long long() const noexcept { return to_integral(*this); } constexpr decimal_fast64_t::operator unsigned long long() const noexcept { return to_integral(*this); } #ifdef BOOST_DECIMAL_HAS_INT128 constexpr decimal_fast64_t::operator detail::builtin_int128_t() const noexcept { return to_integral(*this); } constexpr decimal_fast64_t::operator detail::builtin_uint128_t() const noexcept { return to_integral(*this); } #endif // BOOST_DECIMAL_HAS_INT128 BOOST_DECIMAL_CXX20_CONSTEXPR decimal_fast64_t::operator float() const noexcept { return to_float(*this); } BOOST_DECIMAL_CXX20_CONSTEXPR decimal_fast64_t::operator double() const noexcept { return to_float(*this); } #ifndef BOOST_DECIMAL_UNSUPPORTED_LONG_DOUBLE BOOST_DECIMAL_CXX20_CONSTEXPR decimal_fast64_t::operator long double() const noexcept { return to_float(*this); } #endif #ifdef BOOST_DECIMAL_HAS_FLOAT16 constexpr decimal_fast64_t::operator std::float16_t() const noexcept { return static_cast(to_float(*this)); } #endif #ifdef BOOST_DECIMAL_HAS_FLOAT32 constexpr decimal_fast64_t::operator std::float32_t() const noexcept { return static_cast(to_float(*this)); } #endif #ifdef BOOST_DECIMAL_HAS_FLOAT64 constexpr decimal_fast64_t::operator std::float64_t() const noexcept { return static_cast(to_float(*this)); } #endif #ifdef BOOST_DECIMAL_HAS_BRAINFLOAT16 constexpr decimal_fast64_t::operator std::bfloat16_t() const noexcept { return static_cast(to_float(*this)); } #endif template && (detail::decimal_val_v > detail::decimal_val_v), bool>> constexpr decimal_fast64_t::operator Decimal() const noexcept { return to_decimal(*this); } template && (detail::decimal_val_v <= detail::decimal_val_v), bool>> constexpr decimal_fast64_t::operator Decimal() const noexcept { return to_decimal(*this); } constexpr auto operator+(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> decimal_fast64_t { #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(lhs) || not_finite(rhs)) { if (isinf(lhs) && isinf(rhs) && signbit(lhs) != signbit(rhs)) { return direct_init_d64(detail::d64_fast_qnan, 0, false); } return detail::check_non_finite(lhs, rhs); } #endif return detail::add_impl(lhs, rhs); } template constexpr auto operator+(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { using promoted_significand_type = detail::promote_significand_t; using exp_type = decimal_fast64_t::biased_exponent_type; #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(lhs)) { return detail::check_non_finite(lhs); } #endif auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; exp_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); const auto final_sig_rhs {static_cast(sig_rhs)}; return detail::add_impl( detail::decimal_fast64_t_components{lhs.significand_, lhs.biased_exponent(), lhs.sign_}, detail::decimal_fast64_t_components{final_sig_rhs, exp_rhs, (rhs < 0)} ); } template constexpr auto operator+(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { return rhs + lhs; } constexpr auto operator-(const decimal_fast64_t lhs, decimal_fast64_t rhs) noexcept -> decimal_fast64_t { #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(lhs) || not_finite(rhs)) { if (isinf(lhs) && isinf(rhs) && signbit(lhs) == signbit(rhs)) { return direct_init_d64(detail::d64_fast_qnan, 0, false); } if (isinf(rhs) && !isnan(lhs)) { return -rhs; } return detail::check_non_finite(lhs, rhs); } #endif rhs.sign_ = !rhs.sign_; return detail::add_impl(lhs, rhs); } template constexpr auto operator-(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { using promoted_significand_type = detail::promote_significand_t; using exp_type = decimal_fast64_t::biased_exponent_type; #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(lhs)) { return detail::check_non_finite(lhs); } #endif auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; exp_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); const auto final_sig_rhs {static_cast(sig_rhs)}; return detail::add_impl( detail::decimal_fast64_t_components{lhs.significand_, lhs.biased_exponent(), lhs.sign_}, detail::decimal_fast64_t_components{final_sig_rhs, exp_rhs, !(rhs < 0)} ); } template constexpr auto operator-(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { using promoted_significand_type = detail::promote_significand_t; using exp_type = decimal_fast64_t::biased_exponent_type; #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(rhs)) { if (isinf(rhs)) { return -rhs; } return detail::check_non_finite(rhs); } #endif auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; exp_type exp_lhs {0}; detail::normalize(sig_lhs, exp_lhs); const auto final_sig_lhs {static_cast(sig_lhs)}; return detail::add_impl( detail::decimal_fast64_t_components{final_sig_lhs, exp_lhs, (lhs < 0)}, detail::decimal_fast64_t_components{rhs.significand_, rhs.biased_exponent(), !rhs.sign_} ); } constexpr auto operator*(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> decimal_fast64_t { #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(lhs) || not_finite(rhs)) { if ((isinf(lhs) && rhs == 0) || (isinf(rhs) && lhs == 0)) { return direct_init_d64(detail::d64_fast_qnan, 0, false); } else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs))) { return signbit(lhs) ? lhs : -lhs; } else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs))) { return signbit(lhs) ? -lhs : lhs; } else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs))) { return signbit(rhs) ? rhs : -rhs; } else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs))) { return signbit(rhs) ? -rhs : rhs; } return detail::check_non_finite(lhs, rhs); } #endif return detail::d64_mul_impl(lhs, rhs); } template constexpr auto operator*(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { using promoted_significand_type = detail::promote_significand_t; using exp_type = decimal_fast64_t::biased_exponent_type; #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(lhs)) { if (isinf(lhs) && (signbit(lhs) != (rhs < 0))) { return signbit(lhs) ? lhs : -lhs; } else if (isinf(lhs) && (signbit(lhs) == (rhs < 0))) { return signbit(lhs) ? -lhs : lhs; } return detail::check_non_finite(lhs); } #endif auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; exp_type rhs_exp {0}; detail::normalize(rhs_sig, rhs_exp); auto final_rhs_sig {static_cast(rhs_sig)}; return detail::d64_mul_impl( lhs.significand_, lhs.biased_exponent(), lhs.sign_, final_rhs_sig, rhs_exp, (rhs < 0) ); } template constexpr auto operator*(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { return rhs * lhs; } constexpr auto d64_fast_div_impl(const decimal_fast64_t& lhs, const decimal_fast64_t& rhs, decimal_fast64_t& q, decimal_fast64_t& r) noexcept -> void { const bool sign {lhs.isneg() != rhs.isneg()}; #ifndef BOOST_DECIMAL_FAST_MATH // Check pre-conditions constexpr decimal_fast64_t zero {0, 0}; constexpr decimal_fast64_t nan {direct_init_d64(detail::d64_fast_qnan, 0, false)}; constexpr decimal_fast64_t inf {direct_init_d64(detail::d64_fast_inf, 0, false)}; const auto lhs_fp {fpclassify(lhs)}; const auto rhs_fp {fpclassify(rhs)}; if (lhs_fp != FP_NORMAL || rhs_fp != FP_NORMAL) { if (lhs_fp == FP_NAN || rhs_fp == FP_NAN) { // Operations on an SNAN return a QNAN with the same payload decimal_fast64_t return_nan {}; if (lhs_fp == rhs_fp) { // They are both NANs const bool lhs_signaling {issignaling(lhs)}; const bool rhs_signaling {issignaling(rhs)}; if (!lhs_signaling && rhs_signaling) { return_nan = nan_conversion(rhs); } else { return_nan = lhs_signaling ? nan_conversion(lhs) : lhs; } } else if (lhs_fp == FP_NAN) { return_nan = issignaling(lhs) ? nan_conversion(lhs) : lhs; } else { return_nan = issignaling(rhs) ? nan_conversion(rhs) : rhs; } q = return_nan; r = return_nan; return; } switch (lhs_fp) { case FP_INFINITE: if (rhs_fp == FP_INFINITE) { q = nan; r = nan; } else { q = sign ? -inf : inf; r = zero; } return; case FP_ZERO: if (rhs_fp == FP_ZERO) { q = nan; r = nan; } else { q = sign ? -zero : zero; r = sign ? -zero : zero; } return; default: static_cast(lhs); } switch (rhs_fp) { case FP_ZERO: q = inf; r = zero; return; case FP_INFINITE: q = sign ? -zero : zero; r = lhs; return; default: static_cast(rhs); } } #else static_cast(r); #endif #ifdef BOOST_DECIMAL_DEBUG std::cerr << "sig lhs: " << sig_lhs << "\nexp lhs: " << exp_lhs << "\nsig rhs: " << sig_rhs << "\nexp rhs: " << exp_rhs << std::endl; #endif using unsigned_int128_type = boost::int128::uint128_t; // If rhs is greater than we need to offset the significands to get the correct values // e.g. 4/8 is 0 but 40/8 yields 5 in integer maths constexpr auto offset {std::numeric_limits::digits10 - detail::precision_v}; constexpr auto tens_needed {detail::pow10(static_cast(offset))}; const auto big_sig_lhs {static_cast(lhs.significand_) * tens_needed}; const auto res_sig {big_sig_lhs / rhs.significand_}; const auto res_exp {(lhs.biased_exponent() - offset) - rhs.biased_exponent()}; q = decimal_fast64_t{res_sig, res_exp, sign}; } constexpr auto operator/(const decimal_fast64_t& lhs, const decimal_fast64_t& rhs) noexcept -> decimal_fast64_t { decimal_fast64_t q {}; decimal_fast64_t r {}; d64_fast_div_impl(lhs, rhs, q, r); return q; } template constexpr auto operator/(const decimal_fast64_t lhs, const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { using promoted_significand_type = detail::promote_significand_t; using exp_type = detail::decimal_fast64_t_components::biased_exponent_type; const bool sign {lhs.isneg() != (rhs < 0)}; #ifndef BOOST_DECIMAL_FAST_MATH // Check pre-conditions constexpr decimal_fast64_t zero {0, 0}; constexpr decimal_fast64_t inf {direct_init_d64(detail::d64_fast_inf, 0, false)}; const auto lhs_fp {fpclassify(lhs)}; switch (lhs_fp) { case FP_NAN: return issignaling(lhs) ? nan_conversion(lhs) : lhs;; case FP_INFINITE: return sign ? -lhs : lhs; case FP_ZERO: return sign ? -zero : zero; default: static_cast(lhs); } if (rhs == 0) { return sign ? -inf : inf; } #endif const detail::decimal_fast64_t_components lhs_components {lhs.full_significand(), lhs.biased_exponent(), lhs.isneg()}; auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; exp_type rhs_exp {}; detail::decimal_fast64_t_components rhs_components {detail::shrink_significand(rhs_sig, rhs_exp), rhs_exp, rhs < 0}; return detail::d64_generic_div_impl(lhs_components, rhs_components, sign); } template constexpr auto operator/(const Integer lhs, const decimal_fast64_t rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t) { using promoted_significand_type = detail::promote_significand_t; using exp_type = detail::decimal_fast64_t_components::biased_exponent_type; const bool sign {(lhs < 0) != rhs.isneg()}; #ifndef BOOST_DECIMAL_FAST_MATH // Check pre-conditions constexpr decimal_fast64_t zero {0, 0}; constexpr decimal_fast64_t inf {direct_init_d64(detail::d64_fast_inf, 0, false)}; const auto rhs_fp {fpclassify(rhs)}; switch (rhs_fp) { case FP_NAN: return issignaling(rhs) ? nan_conversion(rhs) : rhs; case FP_INFINITE: return sign ? -zero : zero; case FP_ZERO: return sign ? -inf : inf; default: static_cast(lhs); } #endif const detail::decimal_fast64_t_components rhs_components {rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()}; auto lhs_sig {static_cast(detail::make_positive_unsigned(lhs))}; exp_type lhs_exp {}; const detail::decimal_fast64_t_components lhs_components {detail::shrink_significand(lhs_sig, lhs_exp), lhs_exp, lhs < 0}; return detail::d64_generic_div_impl(lhs_components, rhs_components, sign); } constexpr auto operator%(const decimal_fast64_t lhs, const decimal_fast64_t rhs) noexcept -> decimal_fast64_t { decimal_fast64_t q {}; decimal_fast64_t r {}; d64_fast_div_impl(lhs, rhs, q, r); if (BOOST_DECIMAL_LIKELY(isfinite(lhs) && isfinite(rhs))) { if (rhs == 0 || isinf(q)) { r = std::numeric_limits::quiet_NaN(); } else { detail::generic_mod_impl(lhs, lhs.to_components(), rhs, rhs.to_components(), q, r); } } else if (isinf(lhs) && !isnan(rhs)) { // Modulo of inf is undefined r = std::numeric_limits::quiet_NaN(); } else if (issignaling(lhs)) { r = nan_conversion(lhs); } else if (issignaling(rhs)) { r = nan_conversion(rhs); } else if (isnan(lhs)) { r = lhs; } else if (isnan(rhs)) { r = rhs; } else if (isinf(rhs)) { r = lhs; } return r; } constexpr auto decimal_fast64_t::operator+=(const decimal_fast64_t rhs) noexcept -> decimal_fast64_t & { *this = *this + rhs; return *this; } constexpr auto decimal_fast64_t::operator-=(const decimal_fast64_t rhs) noexcept -> decimal_fast64_t & { *this = *this - rhs; return *this; } constexpr auto decimal_fast64_t::operator*=(const decimal_fast64_t rhs) noexcept -> decimal_fast64_t & { *this = *this * rhs; return *this; } constexpr auto decimal_fast64_t::operator/=(const decimal_fast64_t rhs) noexcept -> decimal_fast64_t & { *this = *this / rhs; return *this; } template constexpr auto decimal_fast64_t::operator+=(const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&) { *this = *this + rhs; return *this; } template constexpr auto decimal_fast64_t::operator-=(const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&) { *this = *this - rhs; return *this; } template constexpr auto decimal_fast64_t::operator*=(const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&) { *this = *this * rhs; return *this; } template constexpr auto decimal_fast64_t::operator/=(const Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast64_t&) { *this = *this / rhs; return *this; } constexpr auto decimal_fast64_t::operator++() noexcept -> decimal_fast64_t& { constexpr decimal_fast64_t one {1, 0}; *this = *this + one; return *this; } constexpr auto decimal_fast64_t::operator++(int) noexcept -> decimal_fast64_t { const auto temp {*this}; ++(*this); return temp; } constexpr auto decimal_fast64_t::operator--() noexcept -> decimal_fast64_t& { constexpr decimal_fast64_t one {1, 0}; *this = *this - one; return *this; } constexpr auto decimal_fast64_t::operator--(int) noexcept -> decimal_fast64_t { const auto temp {*this}; --(*this); return temp; } // Effects: if x is finite, returns its quantum exponent. // Otherwise, a domain error occurs and INT_MIN is returned. constexpr auto quantexpd64f(const decimal_fast64_t x) noexcept -> int { #ifndef BOOST_DECIMAL_FAST_MATH if (!isfinite(x)) { return INT_MIN; } #endif return static_cast(x.unbiased_exponent()); } constexpr auto scalblnd64f(decimal_fast64_t num, const long exp) noexcept -> decimal_fast64_t { #ifndef BOOST_DECIMAL_FAST_MATH constexpr decimal_fast64_t zero {0, 0}; if (num == zero || exp == 0 || not_finite(num)) { return num; } #endif num = decimal_fast64_t(num.significand_, num.biased_exponent() + exp, num.sign_); return num; } constexpr auto scalbnd64f(const decimal_fast64_t num, const int expval) noexcept -> decimal_fast64_t { return scalblnd64f(num, static_cast(expval)); } constexpr auto copysignd64f(decimal_fast64_t mag, const decimal_fast64_t sgn) noexcept -> decimal_fast64_t { mag.sign_ = sgn.sign_; return mag; } #if !defined(BOOST_DECIMAL_DISABLE_CLIB) constexpr decimal_fast64_t::decimal_fast64_t(const char* str, const std::size_t len) { if (str == nullptr || len == 0) { *this = direct_init_d64(detail::d64_fast_qnan, 0, false); BOOST_DECIMAL_THROW_EXCEPTION(std::runtime_error("Can not construct from invalid string")); return; // LCOV_EXCL_LINE } // Normally plus signs aren't allowed auto first {str}; if (*first == '+') { ++first; } decimal_fast64_t v; const auto r {detail::from_chars_general_impl(first, str + len, v, chars_format::general)}; if (r) { *this = v; } else { *this = direct_init_d64(detail::d64_fast_qnan, 0, false); BOOST_DECIMAL_THROW_EXCEPTION(std::runtime_error("Can not construct from invalid string")); } } constexpr decimal_fast64_t::decimal_fast64_t(const char* str) : decimal_fast64_t(str, detail::strlen(str)) {} #ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW inline decimal_fast64_t::decimal_fast64_t(const std::string& str) : decimal_fast64_t(str.c_str(), str.size()) {} #else constexpr decimal_fast64_t::decimal_fast64_t(std::string_view str) : decimal_fast64_t(str.data(), str.size()) {} #endif #endif // BOOST_DECIMAL_DISABLE_CLIB } // namespace decimal } // namespace boost #endif //BOOST_DECIMAL_decimal_fast64_t_HPP