@@ -220,6 +220,21 @@ BOOST_DECIMAL_EXPORT class decimal128_t final
220220 friend constexpr auto read_payload (T value) noexcept
221221 BOOST_DECIMAL_REQUIRES_RETURN(detail::is_ieee_type_v, T, typename T::significand_type);
222222
223+ friend constexpr auto nan_conversion (const decimal128_t value) noexcept -> decimal128_t
224+ {
225+ constexpr auto convert_nan_mask {detail::d128_snan_mask ^ detail::d128_nan_mask};
226+
227+ decimal128_t return_value;
228+ return_value.bits_ = value.bits_ ^ convert_nan_mask;
229+ return return_value;
230+ }
231+
232+ template <typename Decimal>
233+ friend constexpr Decimal detail::check_non_finite (Decimal lhs, Decimal rhs) noexcept ;
234+
235+ template <typename Decimal>
236+ friend constexpr Decimal detail::check_non_finite (Decimal x) noexcept ;
237+
223238public:
224239 // 3.2.4.1 construct/copy/destroy
225240 constexpr decimal128_t () noexcept = default;
@@ -885,6 +900,112 @@ constexpr decimal128_t::decimal128_t(const bool value) noexcept : decimal128_t(s
885900# pragma GCC diagnostic pop
886901#endif
887902
903+ namespace detail {
904+
905+ template <bool >
906+ class numeric_limits_impl128
907+ {
908+ public:
909+
910+ static constexpr bool is_specialized = true ;
911+ static constexpr bool is_signed = true ;
912+ static constexpr bool is_integer = false ;
913+ static constexpr bool is_exact = false ;
914+ static constexpr bool has_infinity = true ;
915+ static constexpr bool has_quiet_NaN = true ;
916+ static constexpr bool has_signaling_NaN = true ;
917+
918+ // These members were deprecated in C++23
919+ #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L)))
920+ static constexpr std::float_denorm_style has_denorm = std::denorm_present;
921+ static constexpr bool has_denorm_loss = true ;
922+ #endif
923+
924+ static constexpr std::float_round_style round_style = std::round_indeterminate;
925+ static constexpr bool is_iec559 = true ;
926+ static constexpr bool is_bounded = true ;
927+ static constexpr bool is_modulo = false ;
928+ static constexpr int digits = 34 ;
929+ static constexpr int digits10 = digits;
930+ static constexpr int max_digits10 = digits;
931+ static constexpr int radix = 10 ;
932+ static constexpr int min_exponent = -6143 ;
933+ static constexpr int min_exponent10 = min_exponent;
934+ static constexpr int max_exponent = 6144 ;
935+ static constexpr int max_exponent10 = max_exponent;
936+ static constexpr bool traps = std::numeric_limits<std::uint64_t >::traps;
937+ static constexpr bool tinyness_before = true ;
938+
939+ // Member functions
940+ static constexpr auto (min) () -> boost::decimal::decimal128_t { return {UINT32_C (1 ), min_exponent}; }
941+ static constexpr auto (max) () -> boost::decimal::decimal128_t { return {boost::int128::uint128_t {UINT64_C (0b1111011010000100110111110101011011000011111000000 ), UINT64_C (0b0011011110001101100011100110001111111111111111111111111111111111 )}, max_exponent - digits + 1 }; }
942+ static constexpr auto lowest () -> boost::decimal::decimal128_t { return {boost::int128::uint128_t {UINT64_C (0b1111011010000100110111110101011011000011111000000 ), UINT64_C (0b0011011110001101100011100110001111111111111111111111111111111111 )}, max_exponent - digits + 1 , construction_sign::negative}; }
943+ static constexpr auto epsilon () -> boost::decimal::decimal128_t { return {UINT32_C (1 ), -digits + 1 }; }
944+ static constexpr auto round_error () -> boost::decimal::decimal128_t { return epsilon (); }
945+ static constexpr auto infinity () -> boost::decimal::decimal128_t { return boost::decimal::from_bits (boost::decimal::detail::d128_inf_mask); }
946+ static constexpr auto quiet_NaN () -> boost::decimal::decimal128_t { return boost::decimal::from_bits (boost::decimal::detail::d128_nan_mask); }
947+ static constexpr auto signaling_NaN () -> boost::decimal::decimal128_t { return boost::decimal::from_bits (boost::decimal::detail::d128_snan_mask); }
948+ static constexpr auto denorm_min () -> boost::decimal::decimal128_t { return {1 , boost::decimal::detail::etiny_v<boost::decimal::decimal128_t >}; }
949+ };
950+
951+ #if !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L
952+
953+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_specialized;
954+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_signed;
955+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_integer;
956+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_exact;
957+ template <bool b> constexpr bool numeric_limits_impl128<b>::has_infinity;
958+ template <bool b> constexpr bool numeric_limits_impl128<b>::has_quiet_NaN;
959+ template <bool b> constexpr bool numeric_limits_impl128<b>::has_signaling_NaN;
960+
961+ // These members were deprecated in C++23
962+ #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L)))
963+ template <bool b> constexpr std::float_denorm_style numeric_limits_impl128<b>::has_denorm;
964+ template <bool b> constexpr bool numeric_limits_impl128<b>::has_denorm_loss;
965+ #endif
966+
967+ template <bool b> constexpr std::float_round_style numeric_limits_impl128<b>::round_style;
968+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_iec559;
969+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_bounded;
970+ template <bool b> constexpr bool numeric_limits_impl128<b>::is_modulo;
971+ template <bool b> constexpr int numeric_limits_impl128<b>::digits;
972+ template <bool b> constexpr int numeric_limits_impl128<b>::digits10;
973+ template <bool b> constexpr int numeric_limits_impl128<b>::max_digits10;
974+ template <bool b> constexpr int numeric_limits_impl128<b>::radix;
975+ template <bool b> constexpr int numeric_limits_impl128<b>::min_exponent;
976+ template <bool b> constexpr int numeric_limits_impl128<b>::min_exponent10;
977+ template <bool b> constexpr int numeric_limits_impl128<b>::max_exponent;
978+ template <bool b> constexpr int numeric_limits_impl128<b>::max_exponent10;
979+ template <bool b> constexpr bool numeric_limits_impl128<b>::traps;
980+ template <bool b> constexpr bool numeric_limits_impl128<b>::tinyness_before;
981+
982+ #endif // !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L
983+
984+ } // namespace detail
985+
986+ } // namespace decimal
987+ } // namespace boost
988+
989+ namespace std {
990+
991+ #ifdef __clang__
992+ # pragma clang diagnostic push
993+ # pragma clang diagnostic ignored "-Wmismatched-tags"
994+ #endif
995+
996+ template <>
997+ class numeric_limits <boost::decimal::decimal128_t > :
998+ public boost::decimal::detail::numeric_limits_impl128<true > {};
999+
1000+ #ifdef __clang__
1001+ # pragma clang diagnostic pop
1002+ #endif
1003+
1004+ } // namespace std
1005+
1006+ namespace boost {
1007+ namespace decimal {
1008+
8881009#if defined(__clang__)
8891010# pragma clang diagnostic push
8901011# pragma clang diagnostic ignored "-Wfloat-equal"
@@ -1462,8 +1583,20 @@ constexpr auto d128_div_impl(const decimal128_t& lhs, const decimal128_t& rhs, d
14621583
14631584 if (lhs_fp == FP_NAN || rhs_fp == FP_NAN)
14641585 {
1465- q = nan;
1466- r = nan;
1586+ // Operations on an SNAN return a QNAN with the same payload
1587+ decimal128_t return_nan {};
1588+ if (lhs_fp == FP_NAN)
1589+ {
1590+ return_nan = issignaling (lhs) ? nan_conversion (lhs) : lhs;
1591+ }
1592+ else
1593+ {
1594+ return_nan = issignaling (rhs) ? nan_conversion (rhs) : rhs;
1595+ }
1596+
1597+ q = return_nan;
1598+ r = return_nan;
1599+
14671600 return ;
14681601 }
14691602
@@ -1579,7 +1712,7 @@ constexpr auto operator+(const decimal128_t lhs, const Integer rhs) noexcept
15791712 #ifndef BOOST_DECIMAL_FAST_MATH
15801713 if (not_finite (lhs))
15811714 {
1582- return lhs;
1715+ return detail::check_non_finite ( lhs) ;
15831716 }
15841717 #endif
15851718
@@ -1643,7 +1776,7 @@ constexpr auto operator-(const decimal128_t lhs, const Integer rhs) noexcept
16431776 #ifndef BOOST_DECIMAL_FAST_MATH
16441777 if (not_finite (lhs))
16451778 {
1646- return lhs;
1779+ return detail::check_non_finite ( lhs) ;
16471780 }
16481781 #endif
16491782
@@ -1672,7 +1805,7 @@ constexpr auto operator-(const Integer lhs, const decimal128_t rhs) noexcept
16721805 #ifndef BOOST_DECIMAL_FAST_MATH
16731806 if (not_finite (rhs))
16741807 {
1675- return rhs;
1808+ return detail::check_non_finite ( rhs) ;
16761809 }
16771810 #endif
16781811
@@ -1723,7 +1856,7 @@ constexpr auto operator*(const decimal128_t lhs, const Integer rhs) noexcept
17231856 #ifndef BOOST_DECIMAL_FAST_MATH
17241857 if (not_finite (lhs))
17251858 {
1726- return lhs;
1859+ return detail::check_non_finite ( lhs) ;
17271860 }
17281861 #endif
17291862
@@ -1767,8 +1900,7 @@ constexpr auto operator/(const decimal128_t lhs, const Integer rhs) noexcept
17671900 #ifndef BOOST_DECIMAL_FAST_MATH
17681901 // Check pre-conditions
17691902 constexpr decimal128_t zero {0 , 0 };
1770- constexpr decimal128_t nan {boost::decimal::from_bits (boost::decimal::detail::d128_snan_mask)};
1771- constexpr decimal128_t inf {boost::decimal::from_bits (boost::decimal::detail::d128_inf_mask)};
1903+ constexpr decimal128_t inf {from_bits (detail::d128_inf_mask)};
17721904
17731905 const bool sign {lhs.isneg () != (rhs < 0 )};
17741906
@@ -1777,9 +1909,9 @@ constexpr auto operator/(const decimal128_t lhs, const Integer rhs) noexcept
17771909 switch (lhs_fp)
17781910 {
17791911 case FP_NAN:
1780- return nan ;
1912+ return issignaling (lhs) ? nan_conversion (lhs) : lhs ;
17811913 case FP_INFINITE:
1782- return inf ;
1914+ return lhs ;
17831915 case FP_ZERO:
17841916 return sign ? -zero : zero;
17851917 default :
@@ -1810,20 +1942,16 @@ constexpr auto operator/(const Integer lhs, const decimal128_t rhs) noexcept
18101942 #ifndef BOOST_DECIMAL_FAST_MATH
18111943 // Check pre-conditions
18121944 constexpr decimal128_t zero {0 , 0 };
1813- constexpr decimal128_t inf {boost::decimal::from_bits (boost::decimal::detail::d128_inf_mask)};
1814- constexpr decimal128_t nan {boost::decimal::from_bits (boost::decimal::detail::d128_snan_mask)};
1945+ constexpr decimal128_t inf {from_bits (detail::d128_inf_mask)};
18151946
18161947 const bool sign {(lhs < 0 ) != rhs.isneg ()};
18171948
18181949 const auto rhs_fp {fpclassify (rhs)};
18191950
1820- if (rhs_fp == FP_NAN)
1821- {
1822- return nan;
1823- }
1824-
18251951 switch (rhs_fp)
18261952 {
1953+ case FP_NAN:
1954+ return issignaling (rhs) ? nan_conversion (rhs) : rhs;
18271955 case FP_INFINITE:
18281956 return sign ? -zero : zero;
18291957 case FP_ZERO:
@@ -2176,112 +2304,6 @@ constexpr auto scalbnd128(decimal128_t num, const int expval) noexcept -> decima
21762304 return scalblnd128 (num, static_cast <long >(expval));
21772305}
21782306
2179- namespace detail {
2180-
2181- template <bool >
2182- class numeric_limits_impl128
2183- {
2184- public:
2185-
2186- static constexpr bool is_specialized = true ;
2187- static constexpr bool is_signed = true ;
2188- static constexpr bool is_integer = false ;
2189- static constexpr bool is_exact = false ;
2190- static constexpr bool has_infinity = true ;
2191- static constexpr bool has_quiet_NaN = true ;
2192- static constexpr bool has_signaling_NaN = true ;
2193-
2194- // These members were deprecated in C++23
2195- #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L)))
2196- static constexpr std::float_denorm_style has_denorm = std::denorm_present;
2197- static constexpr bool has_denorm_loss = true ;
2198- #endif
2199-
2200- static constexpr std::float_round_style round_style = std::round_indeterminate;
2201- static constexpr bool is_iec559 = true ;
2202- static constexpr bool is_bounded = true ;
2203- static constexpr bool is_modulo = false ;
2204- static constexpr int digits = 34 ;
2205- static constexpr int digits10 = digits;
2206- static constexpr int max_digits10 = digits;
2207- static constexpr int radix = 10 ;
2208- static constexpr int min_exponent = -6143 ;
2209- static constexpr int min_exponent10 = min_exponent;
2210- static constexpr int max_exponent = 6144 ;
2211- static constexpr int max_exponent10 = max_exponent;
2212- static constexpr bool traps = std::numeric_limits<std::uint64_t >::traps;
2213- static constexpr bool tinyness_before = true ;
2214-
2215- // Member functions
2216- static constexpr auto (min) () -> boost::decimal::decimal128_t { return {UINT32_C (1 ), min_exponent}; }
2217- static constexpr auto (max) () -> boost::decimal::decimal128_t { return {boost::int128::uint128_t {UINT64_C (0b1111011010000100110111110101011011000011111000000 ), UINT64_C (0b0011011110001101100011100110001111111111111111111111111111111111 )}, max_exponent - digits + 1 }; }
2218- static constexpr auto lowest () -> boost::decimal::decimal128_t { return {boost::int128::uint128_t {UINT64_C (0b1111011010000100110111110101011011000011111000000 ), UINT64_C (0b0011011110001101100011100110001111111111111111111111111111111111 )}, max_exponent - digits + 1 , construction_sign::negative}; }
2219- static constexpr auto epsilon () -> boost::decimal::decimal128_t { return {UINT32_C (1 ), -digits + 1 }; }
2220- static constexpr auto round_error () -> boost::decimal::decimal128_t { return epsilon (); }
2221- static constexpr auto infinity () -> boost::decimal::decimal128_t { return boost::decimal::from_bits (boost::decimal::detail::d128_inf_mask); }
2222- static constexpr auto quiet_NaN () -> boost::decimal::decimal128_t { return boost::decimal::from_bits (boost::decimal::detail::d128_nan_mask); }
2223- static constexpr auto signaling_NaN () -> boost::decimal::decimal128_t { return boost::decimal::from_bits (boost::decimal::detail::d128_snan_mask); }
2224- static constexpr auto denorm_min () -> boost::decimal::decimal128_t { return {1 , boost::decimal::detail::etiny_v<boost::decimal::decimal128_t >}; }
2225- };
2226-
2227- #if !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L
2228-
2229- template <bool b> constexpr bool numeric_limits_impl128<b>::is_specialized;
2230- template <bool b> constexpr bool numeric_limits_impl128<b>::is_signed;
2231- template <bool b> constexpr bool numeric_limits_impl128<b>::is_integer;
2232- template <bool b> constexpr bool numeric_limits_impl128<b>::is_exact;
2233- template <bool b> constexpr bool numeric_limits_impl128<b>::has_infinity;
2234- template <bool b> constexpr bool numeric_limits_impl128<b>::has_quiet_NaN;
2235- template <bool b> constexpr bool numeric_limits_impl128<b>::has_signaling_NaN;
2236-
2237- // These members were deprecated in C++23
2238- #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L)))
2239- template <bool b> constexpr std::float_denorm_style numeric_limits_impl128<b>::has_denorm;
2240- template <bool b> constexpr bool numeric_limits_impl128<b>::has_denorm_loss;
2241- #endif
2242-
2243- template <bool b> constexpr std::float_round_style numeric_limits_impl128<b>::round_style;
2244- template <bool b> constexpr bool numeric_limits_impl128<b>::is_iec559;
2245- template <bool b> constexpr bool numeric_limits_impl128<b>::is_bounded;
2246- template <bool b> constexpr bool numeric_limits_impl128<b>::is_modulo;
2247- template <bool b> constexpr int numeric_limits_impl128<b>::digits;
2248- template <bool b> constexpr int numeric_limits_impl128<b>::digits10;
2249- template <bool b> constexpr int numeric_limits_impl128<b>::max_digits10;
2250- template <bool b> constexpr int numeric_limits_impl128<b>::radix;
2251- template <bool b> constexpr int numeric_limits_impl128<b>::min_exponent;
2252- template <bool b> constexpr int numeric_limits_impl128<b>::min_exponent10;
2253- template <bool b> constexpr int numeric_limits_impl128<b>::max_exponent;
2254- template <bool b> constexpr int numeric_limits_impl128<b>::max_exponent10;
2255- template <bool b> constexpr bool numeric_limits_impl128<b>::traps;
2256- template <bool b> constexpr bool numeric_limits_impl128<b>::tinyness_before;
2257-
2258- #endif // !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L
2259-
2260- } // namespace detail
2261-
2262- } // namespace decimal
2263- } // namespace boost
2264-
2265- namespace std {
2266-
2267- #ifdef __clang__
2268- # pragma clang diagnostic push
2269- # pragma clang diagnostic ignored "-Wmismatched-tags"
2270- #endif
2271-
2272- template <>
2273- class numeric_limits <boost::decimal::decimal128_t > :
2274- public boost::decimal::detail::numeric_limits_impl128<true > {};
2275-
2276- #ifdef __clang__
2277- # pragma clang diagnostic pop
2278- #endif
2279-
2280- } // namespace std
2281-
2282- namespace boost {
2283- namespace decimal {
2284-
22852307#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
22862308
22872309constexpr decimal128_t::decimal128_t (const char * str, std::size_t len)
0 commit comments