From c4222aa943218c87abde275c918b703cbada7672 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 20 Sep 2024 14:26:53 -0400 Subject: [PATCH 01/77] Improved equality implementations for d32 and d64 --- include/boost/decimal/decimal32.hpp | 13 ++---- include/boost/decimal/decimal64.hpp | 14 ++----- include/boost/decimal/detail/comparison.hpp | 44 +++++++++++++++++++++ 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 4c8e0e6fc..a47f04529 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -212,6 +212,9 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m -> std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_decimal_floating_point_v), bool>; + template + friend constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + public: // 3.2.2.1 construct/copy/destroy: constexpr decimal32() noexcept = default; @@ -1056,15 +1059,7 @@ constexpr auto decimal32::operator-=(Integer rhs) noexcept constexpr auto operator==(decimal32 lhs, decimal32 rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - if (isnan(lhs) || isnan(rhs)) - { - return false; - } - #endif - - return equal_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return equality_impl(lhs, rhs); } template diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index ac44a243a..8bf8b3164 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -219,6 +219,9 @@ BOOST_DECIMAL_EXPORT class decimal64 final // We can super easily combine this into a single op friend constexpr auto not_finite(decimal64 rhs) noexcept -> bool; + template + friend constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + public: // 3.2.3.1 construct/copy/destroy constexpr decimal64() noexcept = default; @@ -1622,16 +1625,7 @@ constexpr auto decimal64::operator%=(decimal64 rhs) noexcept -> decimal64& constexpr auto operator==(decimal64 lhs, decimal64 rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - // Check for IEEE requirement that nan != nan - if (isnan(lhs) || isnan(rhs)) - { - return false; - } - #endif - - return equal_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return equality_impl(lhs, rhs); } template diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 091b81501..0d8721106 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -24,6 +24,50 @@ namespace boost { namespace decimal { +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool +{ + using comp_type = typename DecimalType::significand_type; + + // Step 1: Check for NANs per IEEE 754 + #ifndef BOOST_DECIMAL_FAST_MATH + if (isnan(lhs) || isnan(rhs)) + { + return false; + } + #endif + + // Step 3: Check signs + const auto lhs_neg {lhs.isneg()}; + const auto rhs_neg {rhs.isneg()}; + + if (lhs_neg != rhs_neg) + { + return false; + } + + // Step 4: Check the exponents + // If the difference is greater than we can represent in the significand than we can assume they are different + const auto lhs_exp {lhs.biased_exponent()}; + const auto rhs_exp {rhs.biased_exponent()}; + + const auto delta_exp {lhs_exp - rhs_exp}; + + if (delta_exp > detail::precision_v || delta_exp < -detail::precision_v) + { + return false; + } + + // Step 5: Normalize the significand and compare + auto lhs_sig {lhs.full_significand()}; + auto rhs_sig {rhs.full_significand()}; + + delta_exp >= 0 ? lhs_sig *= detail::pow10(static_cast(delta_exp)) : + rhs_sig *= detail::pow10(static_cast(-delta_exp)); + + return lhs_sig == rhs_sig; +} + template constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, From 738618c61da3c7fb42a9df39e2998189f5f3e852 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 20 Sep 2024 16:27:09 -0400 Subject: [PATCH 02/77] Change d32 less than implementation --- include/boost/decimal/decimal32.hpp | 15 +++-- include/boost/decimal/detail/comparison.hpp | 64 +++++++++++++++++++++ 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index a47f04529..febaa9411 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -215,6 +215,9 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m template friend constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + template + friend constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + public: // 3.2.2.1 construct/copy/destroy: constexpr decimal32() noexcept = default; @@ -1111,8 +1114,7 @@ constexpr auto operator<(decimal32 lhs, decimal32 rhs) noexcept -> bool } #endif - return less_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return sequential_less_impl(lhs, rhs); } template @@ -1156,8 +1158,7 @@ constexpr auto operator<=(decimal32 lhs, decimal32 rhs) noexcept -> bool } #endif - return !less_parts_impl(rhs.full_significand(), rhs.biased_exponent(), rhs.isneg(), - lhs.full_significand(), lhs.biased_exponent(), lhs.isneg()); + return !sequential_less_impl(rhs, lhs); } template @@ -1222,8 +1223,7 @@ constexpr auto operator>(decimal32 lhs, decimal32 rhs) noexcept -> bool } #endif - return less_parts_impl(rhs.full_significand(), rhs.biased_exponent(), rhs.isneg(), - lhs.full_significand(), lhs.biased_exponent(), lhs.isneg()); + return sequential_less_impl(rhs, lhs); } template @@ -1263,8 +1263,7 @@ constexpr auto operator>=(decimal32 lhs, decimal32 rhs) noexcept -> bool } #endif - return !less_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return !sequential_less_impl(lhs, rhs); } template diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 0d8721106..bb8b6f3d2 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -241,6 +241,70 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_type_less_parts_impl(T lhs_sig, U return lhs_sign ? lhs_sig > rhs_sig : lhs_sig < rhs_sig; } +template +constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool +{ + using comp_type = std::uint_fast64_t; + + // Step 1: Handle our non-finite values in their own calling functions + + // Step 2: Check if they are bitwise equal: + /* + if (lhs.bits_ == rhs.bits_) + { + return false; + } + */ + + // Step 3: Decode and compare signs first: + const auto lhs_sign {lhs.isneg()}; + const auto rhs_sign {rhs.isneg()}; + + if (lhs_sign != rhs_sign) + { + return lhs_sign; + } + + // Step 4: Decode the significand and do a trivial comp + auto lhs_sig {static_cast(lhs.full_significand())}; + auto rhs_sig {static_cast(rhs.full_significand())}; + if (lhs_sig == static_cast(0) || rhs_sig == static_cast(0)) + { + return (lhs_sig == rhs_sig) ? false : (lhs_sig == static_cast(0) ? !rhs_sign : lhs_sign); + } + + // Step 5: Decode the exponent and see if we can even compare the significands + auto lhs_exp {lhs.biased_exponent()}; + auto rhs_exp {rhs.biased_exponent()}; + + const auto delta_exp {lhs_exp - rhs_exp}; + constexpr auto max_delta_diff {std::numeric_limits::digits10 - detail::precision_v}; + + if (delta_exp > max_delta_diff || delta_exp < -max_delta_diff) + { + return rhs_sign ? rhs_exp < lhs_exp : rhs_exp > lhs_exp; + } + + // Step 6: Approximate normalization if we need to and then get the answer + if (delta_exp >= 0) + { + lhs_sig *= detail::pow10(static_cast(delta_exp)); + lhs_exp -= delta_exp; + } + else + { + rhs_sig *= detail::pow10(static_cast(-delta_exp)); + rhs_exp += delta_exp; + } + + if (lhs_exp != rhs_exp) + { + return lhs_sign ? lhs_exp > rhs_exp : lhs_exp < rhs_exp; + } + + return lhs_sign ? lhs_sig > rhs_sig : lhs_sig < rhs_sig; +} + template constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, From 7f63f4f203560219ad1eee3cfad059b7e90a6f2c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 20 Sep 2024 16:43:01 -0400 Subject: [PATCH 03/77] Revert changes to decimal64 --- include/boost/decimal/decimal64.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 8bf8b3164..019f0fbe2 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1625,7 +1625,16 @@ constexpr auto decimal64::operator%=(decimal64 rhs) noexcept -> decimal64& constexpr auto operator==(decimal64 lhs, decimal64 rhs) noexcept -> bool { - return equality_impl(lhs, rhs); + #ifndef BOOST_DECIMAL_FAST_MATH + // Check for IEEE requirement that nan != nan + if (isnan(lhs) || isnan(rhs)) + { + return false; + } + #endif + + return equal_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), + rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); } template From cae651c8ba6d9aec04d76a2567017e792576f853 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 23 Sep 2024 15:56:58 -0400 Subject: [PATCH 04/77] Use improved operator== with less than and fix 0s --- include/boost/decimal/decimal64.hpp | 11 +---------- include/boost/decimal/detail/comparison.hpp | 9 +++++---- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 019f0fbe2..8bf8b3164 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1625,16 +1625,7 @@ constexpr auto decimal64::operator%=(decimal64 rhs) noexcept -> decimal64& constexpr auto operator==(decimal64 lhs, decimal64 rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - // Check for IEEE requirement that nan != nan - if (isnan(lhs) || isnan(rhs)) - { - return false; - } - #endif - - return equal_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return equality_impl(lhs, rhs); } template diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index bb8b6f3d2..8f5f9088d 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -51,17 +51,18 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal const auto lhs_exp {lhs.biased_exponent()}; const auto rhs_exp {rhs.biased_exponent()}; + auto lhs_sig {lhs.full_significand()}; + auto rhs_sig {rhs.full_significand()}; + const auto delta_exp {lhs_exp - rhs_exp}; - if (delta_exp > detail::precision_v || delta_exp < -detail::precision_v) + if (delta_exp > detail::precision_v || delta_exp < -detail::precision_v || + ((lhs_sig == static_cast(0)) ^ (rhs_sig == static_cast(0)))) { return false; } // Step 5: Normalize the significand and compare - auto lhs_sig {lhs.full_significand()}; - auto rhs_sig {rhs.full_significand()}; - delta_exp >= 0 ? lhs_sig *= detail::pow10(static_cast(delta_exp)) : rhs_sig *= detail::pow10(static_cast(-delta_exp)); From 02f8de987d7e60df3a6aa560646059af36e7d7a6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 23 Sep 2024 15:57:11 -0400 Subject: [PATCH 05/77] Improve operator< for decimal64 --- include/boost/decimal/decimal64.hpp | 6 ++++-- include/boost/decimal/detail/comparison.hpp | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 8bf8b3164..b693ac1dd 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -222,6 +222,9 @@ BOOST_DECIMAL_EXPORT class decimal64 final template friend constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + template + friend constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + public: // 3.2.3.1 construct/copy/destroy constexpr decimal64() noexcept = default; @@ -1682,8 +1685,7 @@ constexpr auto operator<(decimal64 lhs, decimal64 rhs) noexcept -> bool } #endif - return less_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return sequential_less_impl(lhs, rhs); } template diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 8f5f9088d..f4e56e53f 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -245,7 +245,13 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_type_less_parts_impl(T lhs_sig, U template constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool { - using comp_type = std::uint_fast64_t; + using comp_type = std::conditional_t::value, std::uint_fast64_t, + #ifdef BOOST_DECIMAL_HAS_INT128 + detail::uint128_t + #else + detail::uint128 + #endif + >; // Step 1: Handle our non-finite values in their own calling functions @@ -279,7 +285,7 @@ constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept - auto rhs_exp {rhs.biased_exponent()}; const auto delta_exp {lhs_exp - rhs_exp}; - constexpr auto max_delta_diff {std::numeric_limits::digits10 - detail::precision_v}; + constexpr auto max_delta_diff {std::numeric_limits::digits10 - detail::precision_v}; if (delta_exp > max_delta_diff || delta_exp < -max_delta_diff) { From cd60eb6b26b20af3840969d884cd28d6cd00f88d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 10:39:35 -0400 Subject: [PATCH 06/77] Reduce operations in umul256 --- include/boost/decimal/detail/emulated256.hpp | 21 +++++--------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/include/boost/decimal/detail/emulated256.hpp b/include/boost/decimal/detail/emulated256.hpp index 55df7630a..c76bdcb06 100644 --- a/include/boost/decimal/detail/emulated256.hpp +++ b/include/boost/decimal/detail/emulated256.hpp @@ -551,26 +551,15 @@ constexpr uint256_t umul256_impl(std::uint64_t a_high, std::uint64_t a_low, std: const auto mid_product2 {static_cast(a_high) * b_low}; const auto high_product {static_cast(a_high) * b_high}; - std::uint64_t carry {}; + const auto mid_sum {mid_product1 + mid_product2}; + bool carry {mid_sum < mid_product1}; - const auto mid_combined {mid_product1 + mid_product2}; - if (mid_combined < mid_product1) - { - carry = 1; - } - - const auto mid_combined_high {mid_combined >> 64}; - const auto mid_combined_low {mid_combined << 64}; - - const auto low_sum {low_product + mid_combined_low}; - if (low_sum < low_product) - { - carry += 1; - } + const auto low_sum {low_product + (mid_sum << 64)}; + carry += (low_sum < low_product); uint256_t result {}; result.low = low_sum; - result.high = high_product + mid_combined_high + carry; + result.high = high_product + (mid_sum >> 64) + carry; return result; } From 9feef9a19099838caa485ced8d5ee43b7cd3256a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 11:35:19 -0400 Subject: [PATCH 07/77] Change macro for static variables --- include/boost/decimal/detail/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 7f6d26841..4fc468466 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -264,7 +264,7 @@ typedef unsigned __int128 uint128_t; # define BOOST_DECIMAL_REDUCE_TEST_DEPTH #endif -#ifdef __clang__ +#if defined(__clang__) && __clang_major__ < 19 # define BOOST_DECIMAL_CLANG_STATIC static #else # define BOOST_DECIMAL_CLANG_STATIC From c6927faa0a4c941bba1bd3d9bebfd4fdfd9bc948 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 11:35:45 -0400 Subject: [PATCH 08/77] Refactor numbers implementation to fix static specializations --- include/boost/decimal/numbers.hpp | 486 +++++++++++++++++------------- 1 file changed, 284 insertions(+), 202 deletions(-) diff --git a/include/boost/decimal/numbers.hpp b/include/boost/decimal/numbers.hpp index d99b12fbe..7c2773713 100644 --- a/include/boost/decimal/numbers.hpp +++ b/include/boost/decimal/numbers.hpp @@ -10,224 +10,306 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include #endif -namespace boost { namespace decimal { namespace numbers { +namespace boost { +namespace decimal { +namespace numbers { + +namespace detail { + +template < 128, bool> = true> +constexpr auto e_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(2718281828459045235), -18}; +} + +template >= 128, bool> = true> +constexpr auto e_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(147358353192158), UINT64_C(5661142159003925334)}, -33}; +} + +template < 128, bool> = true> +constexpr auto log2e_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(1442695040888963407), -18}; +} + +template >= 128, bool> = true> +constexpr auto log2e_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(78208654878293), UINT64_C(16395798456599530402)}, -33}; +} + +template < 128, bool> = true> +constexpr auto log10e_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(4342944819032518277), -19}; +} + +template >= 128, bool> = true> +constexpr auto log10e_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(235431510388986), UINT64_C(2047877485384264674)}, -34}; +} + +template < 128, bool> = true> +constexpr auto log10_2_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(3010299956639811952), -19}; +} + +template >= 128, bool> = true> +constexpr auto log10_2_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(163188687641095), UINT64_C(3612628795761985410)}, -34}; +} + +template < 128, bool> = true> +constexpr auto pi_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(3141592653589793238), -18}; +} + +template >= 128, bool> = true> +constexpr auto pi_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(170306079004327), UINT64_C(13456286628489437068)}, -33}; +} + +template < 128, bool> = true> +constexpr auto pi_over_four_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(7853981633974483096), -19}; +} + +template >= 128, bool> = true> +constexpr auto pi_over_four_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(42576519751081932), UINT64_C(6764235707220873609)}, -38}; +} + +template < 128, bool> = true> +constexpr auto inv_pi_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(3183098861837906715), -19}; +} + +template >= 128, bool> = true> +constexpr auto inv_pi_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(172556135062039), UINT64_C(13820348844234745256)}, -34}; +} + +template < 128, bool> = true> +constexpr auto inv_sqrtpi_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(5641895835477562869), -19}; +} + +template >= 128, bool> = true> +constexpr auto inv_sqrtpi_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(305847786088084), UINT64_C(12695685840195063976)}, -34}; +} + +template < 128, bool> = true> +constexpr auto ln2_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(6931471805599453094), -19}; +} + +template >= 128, bool> = true> +constexpr auto ln2_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(375755839507647), UINT64_C(8395602002641374208)}, -34}; +} + +template < 128, bool> = true> +constexpr auto ln10_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(2302585092994045684), -18}; +} + +template >= 128, bool> = true> +constexpr auto ln10_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(124823388007844), UINT64_C(1462833818723808456)}, -33}; +} + +template < 128, bool> = true> +constexpr auto sqrt2_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(1414213562373095049), -18}; +} + +template >= 128, bool> = true> +constexpr auto sqrt2_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(76664670834168), UINT64_C(12987834932751794202)}, -33}; +} + +template < 128, bool> = true> +constexpr auto sqrt3_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(1732050807568877294), -18}; +} + +template >= 128, bool> = true> +constexpr auto sqrt3_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(93894662421072), UINT64_C(8437766544231453518)}, -33}; +} + +template < 128, bool> = true> +constexpr auto sqrt10_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(3162277660168379332), -18}; +} + +template >= 128, bool> = true> +constexpr auto sqrt10_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(171427415457846), UINT64_C(13450487317535253574)}, -33}; +} + +template < 128, bool> = true> +constexpr auto cbrt2_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(1259921049894873165), -18}; +} + +template >= 128, bool> = true> +constexpr auto cbrt2_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(68300456972811), UINT64_C(17628749411094165652)}, -33}; +} + +template < 128, bool> = true> +constexpr auto cbrt10_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(2154434690031883722), -18}; +} + +template >= 128, bool> = true> +constexpr auto cbrt10_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(116792138570535), UINT64_C(2467411419527284790)}, -33}; +} + +template < 128, bool> = true> +constexpr auto inv_sqrt2_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(7071067811865475244), -19}; +} + +template >= 128, bool> = true> +constexpr auto inv_sqrt2_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(383323354170843), UINT64_C(9598942442630316202)}, -34}; +} + +template < 128, bool> = true> +constexpr auto inv_sqrt3_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(5773502691896257645), -19}; +} + +template >= 128, bool> = true> +constexpr auto inv_sqrt3_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(312982208070241), UINT64_C(9679144407061960114)}, -34}; +} + +template < 128, bool> = true> +constexpr auto egamma_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(5772156649015328606), -19}; +} + +template >= 128, bool> = true> +constexpr auto egamma_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(312909238939453), UINT64_C(7916302232898517972)}, -34}; +} + +template < 128, bool> = true> +constexpr auto phi_v() noexcept -> DecimalType +{ + return DecimalType{UINT64_C(1618033988749894848), -18}; +} + +template >= 128, bool> = true> +constexpr auto phi_v() noexcept -> DecimalType +{ + return DecimalType{boost::decimal::detail::uint128{UINT64_C(87713798287901), UINT64_C(2061523135646567614)}, -33}; +} + +} // Namespace detail + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec e_v = detail::e_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec log2e_v = detail::log2e_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec log10e_v = detail::log10e_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec log10_2_v = detail::log10_2_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec pi_v = detail::pi_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec pi_over_four_v = detail::pi_over_four_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_pi_v = detail::inv_pi_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_sqrtpi_v = detail::inv_sqrtpi_v(); -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec e_v = Dec{UINT64_C(2718281828459045235), -18}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec ln2_v = detail::ln2_v(); + +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec ln10_v = detail::ln10_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 e_v = decimal128{detail::uint128{UINT64_C(147358353192158), - UINT64_C(5661142159003925334)}, -33}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec sqrt2_v = detail::sqrt2_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast e_v = decimal128_fast{detail::uint128{UINT64_C(147358353192158), - UINT64_C(5661142159003925334)}, -33}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec sqrt3_v = detail::sqrt3_v(); -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec log2e_v = Dec{UINT64_C(1442695040888963407), -18}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec sqrt10_v = detail::sqrt10_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 log2e_v = decimal128{detail::uint128{UINT64_C(78208654878293), - UINT64_C(16395798456599530402)}, -33}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec cbrt2_v = detail::cbrt2_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast log2e_v = decimal128_fast{detail::uint128{UINT64_C(78208654878293), - UINT64_C(16395798456599530402)}, -33}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec cbrt10_v = detail::cbrt10_v(); -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec log10e_v = Dec{UINT64_C(4342944819032518277), -19}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_sqrt2_v = detail::inv_sqrt2_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 log10e_v = decimal128{detail::uint128{UINT64_C(235431510388986), - UINT64_C(2047877485384264674)}, -34}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_sqrt3_v = detail::inv_sqrt3_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast log10e_v = decimal128_fast{detail::uint128{UINT64_C(235431510388986), - UINT64_C(2047877485384264674)}, -34}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec egamma_v = detail::egamma_v(); -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec log10_2_v = Dec{UINT64_C(3010299956639811952), -19}; +BOOST_DECIMAL_EXPORT template , bool> = true> +BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec phi_v = detail::phi_v(); -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 log10_2_v = decimal128{detail::uint128{UINT64_C(163188687641095), - UINT64_C(3612628795761985410)}, -34}; -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast log10_2_v = decimal128_fast{detail::uint128{UINT64_C(163188687641095), - UINT64_C(3612628795761985410)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec pi_v = Dec{UINT64_C(3141592653589793238), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 pi_v = decimal128{detail::uint128{UINT64_C(170306079004327), - UINT64_C(13456286628489437068)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast pi_v = decimal128_fast{detail::uint128{UINT64_C(170306079004327), - UINT64_C(13456286628489437068)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec pi_over_four_v = Dec{UINT64_C(7853981633974483096), -19}; - -// For extraction of the 128-bit approximate value of pi/4, see also: https://godbolt.org/z/fcjjGP7bY -// See also: -// N[Pi/4, 37] -// 0.7853981633974483096156608458198757210 -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 pi_over_four_v = decimal128{detail::uint128{UINT64_C(42576519751081932), - UINT64_C(6764235707220873609)}, -38}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast pi_over_four_v = decimal128_fast{detail::uint128{UINT64_C(42576519751081932), - UINT64_C(6764235707220873609)}, -38}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_pi_v = Dec{UINT64_C(3183098861837906715), -19}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 inv_pi_v = decimal128{detail::uint128{UINT64_C(172556135062039), - UINT64_C(13820348844234745256)}, -34}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast inv_pi_v = decimal128_fast{detail::uint128{UINT64_C(172556135062039), - UINT64_C(13820348844234745256)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_sqrtpi_v = Dec{UINT64_C(5641895835477562869), -19}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 inv_sqrtpi_v = decimal128{detail::uint128{UINT64_C(305847786088084), - UINT64_C(12695685840195063976)}, -34}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast inv_sqrtpi_v = decimal128_fast{detail::uint128{UINT64_C(305847786088084), - UINT64_C(12695685840195063976)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec ln2_v = Dec{UINT64_C(6931471805599453094), -19}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 ln2_v = decimal128{detail::uint128{UINT64_C(375755839507647), - UINT64_C(8395602002641374208)}, -34}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast ln2_v = decimal128_fast{detail::uint128{UINT64_C(375755839507647), - UINT64_C(8395602002641374208)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec ln10_v = Dec{UINT64_C(2302585092994045684), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 ln10_v = decimal128{detail::uint128{UINT64_C(124823388007844), - UINT64_C(1462833818723808456)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast ln10_v = decimal128_fast{detail::uint128{UINT64_C(124823388007844), - UINT64_C(1462833818723808456)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec sqrt2_v = Dec{UINT64_C(1414213562373095049), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 sqrt2_v = decimal128{detail::uint128{UINT64_C(76664670834168), - UINT64_C(12987834932751794202)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast sqrt2_v = decimal128_fast{detail::uint128{UINT64_C(76664670834168), - UINT64_C(12987834932751794202)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec sqrt3_v = Dec{UINT64_C(1732050807568877294), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 sqrt3_v = decimal128{detail::uint128{UINT64_C(93894662421072), - UINT64_C(8437766544231453518)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast sqrt3_v = decimal128_fast{detail::uint128{UINT64_C(93894662421072), - UINT64_C(8437766544231453518)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec sqrt10_v = Dec{UINT64_C(3162277660168379332), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 sqrt10_v = decimal128{detail::uint128{UINT64_C(171427415457846), - UINT64_C(13450487317535253574)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast sqrt10_v = decimal128_fast{detail::uint128{UINT64_C(171427415457846), - UINT64_C(13450487317535253574)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec cbrt2_v = Dec{UINT64_C(1259921049894873165), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 cbrt2_v = decimal128{detail::uint128{UINT64_C(68300456972811), - UINT64_C(17628749411094165652)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast cbrt2_v = decimal128_fast{detail::uint128{UINT64_C(68300456972811), - UINT64_C(17628749411094165652)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec cbrt10_v = Dec{UINT64_C(2154434690031883722), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 cbrt10_v = decimal128{detail::uint128{UINT64_C(116792138570535), - UINT64_C(2467411419527284790)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast cbrt10_v = decimal128_fast{detail::uint128{UINT64_C(116792138570535), - UINT64_C(2467411419527284790)}, -33}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_sqrt2_v = Dec{UINT64_C(7071067811865475244), -19}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 inv_sqrt2_v = decimal128{detail::uint128{UINT64_C(383323354170843), - UINT64_C(9598942442630316202)}, -34}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast inv_sqrt2_v = decimal128_fast{detail::uint128{UINT64_C(383323354170843), - UINT64_C(9598942442630316202)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec inv_sqrt3_v = Dec{UINT64_C(5773502691896257645), -19}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 inv_sqrt3_v = decimal128{detail::uint128{UINT64_C(312982208070241), - UINT64_C(9679144407061960114)}, -34}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast inv_sqrt3_v = decimal128_fast{detail::uint128{UINT64_C(312982208070241), - UINT64_C(9679144407061960114)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec egamma_v = Dec{UINT64_C(5772156649015328606), -19}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 egamma_v = decimal128{detail::uint128{UINT64_C(312909238939453), - UINT64_C(7916302232898517972)}, -34}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast egamma_v = decimal128_fast{detail::uint128{UINT64_C(312909238939453), - UINT64_C(7916302232898517972)}, -34}; - -BOOST_DECIMAL_EXPORT template , bool> = true> -BOOST_DECIMAL_CONSTEXPR_VARIABLE Dec phi_v = Dec{UINT64_C(1618033988749894848), -18}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128 phi_v = decimal128{detail::uint128{UINT64_C(87713798287901), - UINT64_C(2061523135646567614)}, -33}; - -BOOST_DECIMAL_EXPORT template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION decimal128_fast phi_v = decimal128_fast{detail::uint128{UINT64_C(87713798287901), - UINT64_C(2061523135646567614)}, -33}; +// Explicitly defaulted variables like the STL provides BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR_VARIABLE auto e {e_v}; BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR_VARIABLE auto log10_2 {log10_2_v}; From ad2b7cf717a611ca9fb54daf9a897c93d4e19b96 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 12:24:31 -0400 Subject: [PATCH 09/77] Use |= instead of += on bool --- include/boost/decimal/detail/emulated256.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/emulated256.hpp b/include/boost/decimal/detail/emulated256.hpp index c76bdcb06..41973640c 100644 --- a/include/boost/decimal/detail/emulated256.hpp +++ b/include/boost/decimal/detail/emulated256.hpp @@ -555,7 +555,7 @@ constexpr uint256_t umul256_impl(std::uint64_t a_high, std::uint64_t a_low, std: bool carry {mid_sum < mid_product1}; const auto low_sum {low_product + (mid_sum << 64)}; - carry += (low_sum < low_product); + carry |= (low_sum < low_product); uint256_t result {}; result.low = low_sum; From a2265f3d1972883e041df321169497a661ec02f4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 12:44:08 -0400 Subject: [PATCH 10/77] Refactor attributes --- include/boost/decimal/detail/attributes.hpp | 165 +++++++++++--------- 1 file changed, 92 insertions(+), 73 deletions(-) diff --git a/include/boost/decimal/detail/attributes.hpp b/include/boost/decimal/detail/attributes.hpp index f97a3176f..2f44e2543 100644 --- a/include/boost/decimal/detail/attributes.hpp +++ b/include/boost/decimal/detail/attributes.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include @@ -19,102 +21,119 @@ namespace decimal { namespace detail { // Values from IEEE 754-2019 table 3.6 +namespace impl { + +template +constexpr auto storage_width_v() noexcept -> int +{ + return decimal_val_v < 64 ? 32 : + decimal_val_v < 128 ? 64 : 128; +} + +template +constexpr auto precision_v() noexcept -> int +{ + return decimal_val_v < 64 ? 7 : + decimal_val_v < 128 ? 16 : 34; +} + +template +constexpr auto bias_v() noexcept -> int +{ + return decimal_val_v < 64 ? 101 : + decimal_val_v < 128 ? 398 : 6176; +} + +template +constexpr auto max_biased_exp_v() noexcept -> int +{ + return decimal_val_v < 64 ? 191 : + decimal_val_v < 128 ? 767 : 12287; +} + +template +constexpr auto emax_v() noexcept -> int +{ + return decimal_val_v < 64 ? 96 : + decimal_val_v < 128 ? 384 : 6144; +} + +template +constexpr auto emin_v() noexcept -> int +{ + return decimal_val_v < 64 ? -95 : + decimal_val_v < 128 ? -383 : -6143; +} + +template +constexpr auto combination_field_width_v() noexcept -> int +{ + return decimal_val_v < 64 ? 11 : + decimal_val_v < 128 ? 13 : 17; +} + +template +constexpr auto trailing_significand_field_width_v() noexcept -> int +{ + return decimal_val_v < 64 ? 20 : + decimal_val_v < 128 ? 50 : 110; +} + +template < 128, bool> = true> +constexpr auto max_significand_v() noexcept +{ + return decimal_val_v < 64 ? 9'999'999 : 9'999'999'999'999'999; +} + +template >= 128, bool> = true> +constexpr auto max_significand_v() noexcept +{ + return std::is_same::value ? uint128{UINT64_C(0b1111111111'1111111111'1111111111'1111111111'111111), UINT64_MAX} : + uint128{UINT64_C(542101086242752), UINT64_C(4003012203950112767)}; +} + +template +constexpr auto max_string_length_v() noexcept -> int +{ + return decimal_val_v < 64 ? 15 : + decimal_val_v < 128 ? 25 : 41; +} + +} // namespace impl template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto storage_width_v = std::is_same::value || std::is_same::value ? 32 : 64; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto storage_width_v = 128; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto storage_width_v = 128; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto storage_width_v = impl::storage_width_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto precision_v = std::is_same::value || std::is_same::value ? 7 : 16; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto precision_v = 34; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto precision_v = 34; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto precision_v = impl::precision_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto bias_v = std::is_same::value || std::is_same::value ? 101 : 398; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto bias_v = 6176; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto bias_v = 6176; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto bias_v = impl::bias_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto max_biased_exp_v = std::is_same::value || std::is_same::value ? 191 : 767; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto max_biased_exp_v = 12287; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto max_biased_exp_v = 12287; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto max_biased_exp_v = impl::max_biased_exp_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto emax_v = std::is_same::value || std::is_same::value ? 96 : 384; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto emax_v = 6144; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto emax_v = 6144; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto emax_v = impl::emax_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto emin_v = std::is_same::value || std::is_same::value ? -95 : -383; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto emin_v = -6143; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto emin_v = -6143; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto emin_v = impl::emin_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto etiny_v = -bias_v; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto etiny_v = -impl::bias_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto combination_field_width_v = std::is_same::value || std::is_same::value ? 11 : 13; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto combination_field_width_v = 17; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto combination_field_width_v = 17; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto combination_field_width_v = impl::combination_field_width_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto trailing_significand_field_width_v = std::is_same::value || std::is_same::value ? 20 : 50; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto trailing_significand_field_width_v = 110; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto trailing_significand_field_width_v = 110; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto trailing_significand_field_width_v = impl::trailing_significand_field_width_v(); template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto max_significand_v = std::is_same::value || std::is_same::value ? 9'999'999 : 9'999'999'999'999'999; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto max_significand_v = - uint128{UINT64_C(0b1111111111'1111111111'1111111111'1111111111'111111), UINT64_MAX}; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto max_significand_v = - uint128{UINT64_C(542101086242752), UINT64_C(4003012203950112767)}; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto max_significand_v = impl::max_significand_v(); // sign + decimal digits + '.' + 'e' + '+/-' + max digits of exponent + null term template , bool> = true> -BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto max_string_length_v = std::is_same::value || std::is_same::value ? 15 : 25; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto max_string_length_v = 41; - -template <> -BOOST_DECIMAL_CONSTEXPR_VARIABLE_SPECIALIZATION auto max_string_length_v = 41; +BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto max_string_length_v = impl::max_string_length_v(); BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto storage_width {storage_width_v}; BOOST_DECIMAL_ATTRIBUTE_UNUSED BOOST_DECIMAL_CONSTEXPR_VARIABLE auto precision {precision_v}; From 13726f3179d9aad4d998e16fcd0769933c97d7b4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 14:21:19 -0400 Subject: [PATCH 11/77] Add workaround for broken compiler support --- include/boost/decimal/detail/comparison.hpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index f4e56e53f..f968185a0 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include @@ -246,8 +247,14 @@ template constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool { using comp_type = std::conditional_t::value, std::uint_fast64_t, - #ifdef BOOST_DECIMAL_HAS_INT128 - detail::uint128_t + // GCC less than 10 in non-GNU mode, Clang < 10 and MinGW all have issues with the built-in u128, + // so use the emulated one + #if defined(BOOST_DECIMAL_HAS_INT128) + #if ( (defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10) || (defined(__clang__) && __clang_major__ < 13) ) + detail::uint128 + # else + detail::uint128_t + # endif #else detail::uint128 #endif From a1db02009ec9c94d2775cf1ade1de31d326a77f8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 15:15:42 -0400 Subject: [PATCH 12/77] Improve decimal128 multiplication --- include/boost/decimal/decimal128.hpp | 6 ---- include/boost/decimal/detail/mul_impl.hpp | 39 +++++++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index b0e0b2130..290ae153b 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -1682,15 +1682,9 @@ constexpr auto operator*(decimal128 lhs, decimal128 rhs) noexcept -> decimal128 auto lhs_sig {lhs.full_significand()}; auto lhs_exp {lhs.biased_exponent()}; - const auto lhs_zeros {detail::remove_trailing_zeros(lhs_sig)}; - lhs_sig = lhs_zeros.trimmed_number; - lhs_exp += static_cast(lhs_zeros.number_of_removed_zeros); auto rhs_sig {rhs.full_significand()}; auto rhs_exp {rhs.biased_exponent()}; - const auto rhs_zeros {detail::remove_trailing_zeros(rhs_sig)}; - rhs_sig = rhs_zeros.trimmed_number; - rhs_exp += static_cast(rhs_zeros.number_of_removed_zeros); return detail::d128_mul_impl( lhs_sig, lhs_exp, lhs.isneg(), diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 6855223e5..7bc3ee6f8 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -171,22 +171,35 @@ constexpr auto d128_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, { bool sign {lhs_sign != rhs_sign}; - // Once we have the normalized significands and exponents all we have to do is - // multiply the significands and add the exponents - auto res_sig {detail::umul256(lhs_sig, rhs_sig)}; - auto res_exp {lhs_exp + rhs_exp}; - - const auto sig_dig {detail::num_digits(res_sig)}; + const auto lhs_dig {detail::num_digits(lhs_sig)}; + const auto rhs_dig {detail::num_digits(rhs_sig)}; - if (sig_dig > std::numeric_limits::digits10) + // If we can avoid it don't do 256 bit multiplication because it is slow + if (lhs_dig * rhs_dig <= std::numeric_limits::digits10) { - const auto digit_delta {sig_dig - std::numeric_limits::digits10}; - res_sig /= detail::uint256_t(pow10(detail::uint128(digit_delta))); - res_exp += digit_delta; + auto res_sig {lhs_sig * rhs_sig}; + auto res_exp {lhs_exp + rhs_exp}; + return {res_sig, res_exp, sign}; + } + else + { + // Once we have the normalized significands and exponents all we have to do is + // multiply the significands and add the exponents + auto res_sig {detail::umul256(lhs_sig, rhs_sig)}; + auto res_exp {lhs_exp + rhs_exp}; + + const auto sig_dig {detail::num_digits(res_sig)}; + + if (sig_dig > std::numeric_limits::digits10) + { + const auto digit_delta {sig_dig - std::numeric_limits::digits10}; + res_sig /= detail::uint256_t(pow10(detail::uint128(digit_delta))); + res_exp += digit_delta; + } + + BOOST_DECIMAL_ASSERT(res_sig.high == uint128(0, 0)); + return {res_sig.low, res_exp, sign}; } - - BOOST_DECIMAL_ASSERT(res_sig.high == uint128(0,0)); - return {res_sig.low, res_exp, sign}; } template Date: Tue, 24 Sep 2024 15:22:26 -0400 Subject: [PATCH 13/77] Trim trailing zeros for dec128_fast mul --- include/boost/decimal/decimal128_fast.hpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index abf5f9280..0f79cf925 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -909,9 +909,21 @@ constexpr auto operator*(decimal128_fast lhs, decimal128_fast rhs) noexcept -> d } #endif - return detail::d128_fast_mul_impl( - lhs.significand_, lhs.biased_exponent(), lhs.sign_, - rhs.significand_, rhs.biased_exponent(), rhs.sign_); + auto lhs_sig {lhs.full_significand()}; + auto lhs_exp {lhs.biased_exponent()}; + const auto lhs_zeros {detail::remove_trailing_zeros(lhs_sig)}; + lhs_sig = lhs_zeros.trimmed_number; + lhs_exp += static_cast(lhs_zeros.number_of_removed_zeros); + + auto rhs_sig {rhs.full_significand()}; + auto rhs_exp {rhs.biased_exponent()}; + const auto rhs_zeros {detail::remove_trailing_zeros(rhs_sig)}; + rhs_sig = rhs_zeros.trimmed_number; + rhs_exp += static_cast(rhs_zeros.number_of_removed_zeros); + + return detail::d128_mul_impl( + lhs_sig, lhs_exp, lhs.sign_, + rhs_sig, rhs_exp, rhs.sign_); } template From c4bd2af4728cd69d23b3d48211d5df7d54b13b4a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 24 Sep 2024 16:00:36 -0400 Subject: [PATCH 14/77] Fix platform dependent shortening error --- include/boost/decimal/detail/mul_impl.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 7bc3ee6f8..29a698cfc 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -165,9 +165,10 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo return {res_sig_64, res_exp, sign}; } -template -constexpr auto d128_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +template +constexpr auto d128_mul_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> ReturnType { bool sign {lhs_sign != rhs_sign}; From a93d704a982e4027114ac3bf61f7bf7d3c6772f3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 09:50:05 -0400 Subject: [PATCH 15/77] Add support for b2 modular builds and boostlook --- build.jam | 20 ++++++++++++++++++++ doc/Jamfile | 6 +++++- test/Jamfile | 9 +++++---- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 build.jam diff --git a/build.jam b/build.jam new file mode 100644 index 000000000..81d2c7580 --- /dev/null +++ b/build.jam @@ -0,0 +1,20 @@ +# Copyright René Ferdinand Rivera Morell 2023-2024 +# Copyright Matt Borland 2024 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +require-b2 5.2 ; + +project /boost/decimal + : common-requirements + include + ; + +explicit + [ alias boost_core ] + [ alias all : boost_decimal test ] + ; + +call-if : boost-library decimal + ; diff --git a/doc/Jamfile b/doc/Jamfile index 459f1723c..55a35f90c 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -1,10 +1,14 @@ # Copyright 2017, 2018 Peter Dimov +# Copyright 2024 Matt Borland # Distributed under the Boost Software License, Version 1.0. # https://www.boost.org/LICENSE_1_0.txt import asciidoctor ; -html decimal.html : decimal.adoc ; +html decimal.html : decimal.adoc + : /boost/boostlook//boostlook + decimal-docinfo-footer.html + ; install html_ : decimal.html : html ; diff --git a/test/Jamfile b/test/Jamfile index 083d458bf..f4998aa32 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -4,13 +4,14 @@ # Distributed under the Boost Software License, Version 1.0. # https://www.boost.org/LICENSE_1_0.txt +require-b2 5.0.1 ; +import-search /boost/config/checks ; +import config : requires ; +import modules ; import testing ; -import ../../config/checks/config : requires ; project : requirements - /boost/charconv//boost_charconv - gcc:-Wall gcc:-Wextra @@ -113,7 +114,7 @@ run test_fixed_width_trunc.cpp ; run test_float_conversion.cpp ; run-fail test_fprintf.cpp ; run test_frexp_ldexp.cpp ; -run test_from_chars.cpp ; +run test_from_chars.cpp /boost/charconv//boost_charconv ; run test_git_issue_266.cpp ; run test_git_issue_271.cpp ; run test_hash.cpp ; From 8b099f7a52938384e5adf12f406e762ab51074b6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 14:01:59 -0400 Subject: [PATCH 16/77] Add encoding table --- include/boost/decimal/dpd_conversion.hpp | 162 +++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 include/boost/decimal/dpd_conversion.hpp diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp new file mode 100644 index 000000000..9b5ed9935 --- /dev/null +++ b/include/boost/decimal/dpd_conversion.hpp @@ -0,0 +1,162 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DPD_CONVERSION_HPP +#define BOOST_DECIMAL_DPD_CONVERSION_HPP + +#include +#include +#include + +#ifndef BOOST_DECIMAL_BUILD_MODULE +#include +#endif + +namespace boost { +namespace decimal { + +namespace detail { + +// See IEEE 754-2008 tables 3-3 and 3-4 for explanation +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint16_t dpd_table[1000] = +{ + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x004, 0x005, + 0x006, 0x007, 0x006, 0x007, 0x008, 0x009, 0x00a, 0x00b, + 0x00c, 0x00d, 0x00e, 0x00f, 0x00a, 0x00b, 0x00c, 0x00d, + 0x00e, 0x00f, 0x00c, 0x00d, 0x00e, 0x00f, 0x00e, 0x00f, + 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, + 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x014, 0x015, + 0x016, 0x017, 0x016, 0x017, 0x018, 0x019, 0x01a, 0x01b, + 0x01c, 0x01d, 0x01e, 0x01f, 0x01a, 0x01b, 0x01c, 0x01d, + 0x01e, 0x01f, 0x01c, 0x01d, 0x01e, 0x01f, 0x01e, 0x01f, + 0x02c, 0x02d, 0x02e, 0x02f, 0x02c, 0x02d, 0x02e, 0x02f, + 0x02b, 0x02f, 0x03c, 0x03d, 0x03e, 0x03f, 0x03c, 0x03d, + 0x03e, 0x03f, 0x03b, 0x03f, 0x040, 0x041, 0x042, 0x043, + 0x044, 0x045, 0x046, 0x047, 0x042, 0x043, 0x044, 0x045, + 0x046, 0x047, 0x044, 0x045, 0x046, 0x047, 0x046, 0x047, + 0x048, 0x049, 0x04a, 0x04b, 0x04c, 0x04d, 0x04e, 0x04f, + 0x04a, 0x04b, 0x04c, 0x04d, 0x04e, 0x04f, 0x04c, 0x04d, + 0x04e, 0x04f, 0x04e, 0x04f, 0x050, 0x051, 0x052, 0x053, + 0x054, 0x055, 0x056, 0x057, 0x052, 0x053, 0x054, 0x055, + 0x056, 0x057, 0x054, 0x055, 0x056, 0x057, 0x056, 0x057, + 0x058, 0x059, 0x05a, 0x05b, 0x05c, 0x05d, 0x05e, 0x05f, + 0x05a, 0x05b, 0x05c, 0x05d, 0x05e, 0x05f, 0x05c, 0x05d, + 0x05e, 0x05f, 0x05e, 0x05f, 0x06c, 0x06d, 0x06e, 0x06f, + 0x06c, 0x06d, 0x06e, 0x06f, 0x06b, 0x06f, 0x07c, 0x07d, + 0x07e, 0x07f, 0x07c, 0x07d, 0x07e, 0x07f, 0x07b, 0x07f, + 0x080, 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, + 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x084, 0x085, + 0x086, 0x087, 0x086, 0x087, 0x088, 0x089, 0x08a, 0x08b, + 0x08c, 0x08d, 0x08e, 0x08f, 0x08a, 0x08b, 0x08c, 0x08d, + 0x08e, 0x08f, 0x08c, 0x08d, 0x08e, 0x08f, 0x08e, 0x08f, + 0x090, 0x091, 0x092, 0x093, 0x094, 0x095, 0x096, 0x097, + 0x092, 0x093, 0x094, 0x095, 0x096, 0x097, 0x094, 0x095, + 0x096, 0x097, 0x096, 0x097, 0x098, 0x099, 0x09a, 0x09b, + 0x09c, 0x09d, 0x09e, 0x09f, 0x09a, 0x09b, 0x09c, 0x09d, + 0x09e, 0x09f, 0x09c, 0x09d, 0x09e, 0x09f, 0x09e, 0x09f, + 0x0ac, 0x0ad, 0x0ae, 0x0af, 0x0ac, 0x0ad, 0x0ae, 0x0af, + 0x0ab, 0x0af, 0x0bc, 0x0bd, 0x0be, 0x0bf, 0x0bc, 0x0bd, + 0x0be, 0x0bf, 0x0bb, 0x0bf, 0x0c0, 0x0c1, 0x0c2, 0x0c3, + 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0c2, 0x0c3, 0x0c4, 0x0c5, + 0x0c6, 0x0c7, 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0c6, 0x0c7, + 0x0c8, 0x0c9, 0x0ca, 0x0cb, 0x0cc, 0x0cd, 0x0ce, 0x0cf, + 0x0ca, 0x0cb, 0x0cc, 0x0cd, 0x0ce, 0x0cf, 0x0cc, 0x0cd, + 0x0ce, 0x0cf, 0x0ce, 0x0cf, 0x0d0, 0x0d1, 0x0d2, 0x0d3, + 0x0d4, 0x0d5, 0x0d6, 0x0d7, 0x0d2, 0x0d3, 0x0d4, 0x0d5, + 0x0d6, 0x0d7, 0x0d4, 0x0d5, 0x0d6, 0x0d7, 0x0d6, 0x0d7, + 0x0d8, 0x0d9, 0x0da, 0x0db, 0x0dc, 0x0dd, 0x0de, 0x0df, + 0x0da, 0x0db, 0x0dc, 0x0dd, 0x0de, 0x0df, 0x0dc, 0x0dd, + 0x0de, 0x0df, 0x0de, 0x0df, 0x0ec, 0x0ed, 0x0ee, 0x0ef, + 0x0ec, 0x0ed, 0x0ee, 0x0ef, 0x0eb, 0x0ef, 0x0fc, 0x0fd, + 0x0fe, 0x0ff, 0x0fc, 0x0fd, 0x0fe, 0x0ff, 0x0fb, 0x0ff, + 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, + 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x104, 0x105, + 0x106, 0x107, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, + 0x10c, 0x10d, 0x10e, 0x10f, 0x10a, 0x10b, 0x10c, 0x10d, + 0x10e, 0x10f, 0x10c, 0x10d, 0x10e, 0x10f, 0x10e, 0x10f, + 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, + 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x114, 0x115, + 0x116, 0x117, 0x116, 0x117, 0x118, 0x119, 0x11a, 0x11b, + 0x11c, 0x11d, 0x11e, 0x11f, 0x11a, 0x11b, 0x11c, 0x11d, + 0x11e, 0x11f, 0x11c, 0x11d, 0x11e, 0x11f, 0x11e, 0x11f, + 0x12c, 0x12d, 0x12e, 0x12f, 0x12c, 0x12d, 0x12e, 0x12f, + 0x12b, 0x12f, 0x13c, 0x13d, 0x13e, 0x13f, 0x13c, 0x13d, + 0x13e, 0x13f, 0x13b, 0x13f, 0x140, 0x141, 0x142, 0x143, + 0x144, 0x145, 0x146, 0x147, 0x142, 0x143, 0x144, 0x145, + 0x146, 0x147, 0x144, 0x145, 0x146, 0x147, 0x146, 0x147, + 0x148, 0x149, 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, + 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, 0x14c, 0x14d, + 0x14e, 0x14f, 0x14e, 0x14f, 0x150, 0x151, 0x152, 0x153, + 0x154, 0x155, 0x156, 0x157, 0x152, 0x153, 0x154, 0x155, + 0x156, 0x157, 0x154, 0x155, 0x156, 0x157, 0x156, 0x157, + 0x158, 0x159, 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, + 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, 0x15c, 0x15d, + 0x15e, 0x15f, 0x15e, 0x15f, 0x16c, 0x16d, 0x16e, 0x16f, + 0x16c, 0x16d, 0x16e, 0x16f, 0x16b, 0x16f, 0x17c, 0x17d, + 0x17e, 0x17f, 0x17c, 0x17d, 0x17e, 0x17f, 0x17b, 0x17f, + 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, + 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, 0x184, 0x185, + 0x186, 0x187, 0x186, 0x187, 0x188, 0x189, 0x18a, 0x18b, + 0x18c, 0x18d, 0x18e, 0x18f, 0x18a, 0x18b, 0x18c, 0x18d, + 0x18e, 0x18f, 0x18c, 0x18d, 0x18e, 0x18f, 0x18e, 0x18f, + 0x190, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, + 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x194, 0x195, + 0x196, 0x197, 0x196, 0x197, 0x198, 0x199, 0x19a, 0x19b, + 0x19c, 0x19d, 0x19e, 0x19f, 0x19a, 0x19b, 0x19c, 0x19d, + 0x19e, 0x19f, 0x19c, 0x19d, 0x19e, 0x19f, 0x19e, 0x19f, + 0x1ac, 0x1ad, 0x1ae, 0x1af, 0x1ac, 0x1ad, 0x1ae, 0x1af, + 0x1ab, 0x1af, 0x1bc, 0x1bd, 0x1be, 0x1bf, 0x1bc, 0x1bd, + 0x1be, 0x1bf, 0x1bb, 0x1bf, 0x1c0, 0x1c1, 0x1c2, 0x1c3, + 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c2, 0x1c3, 0x1c4, 0x1c5, + 0x1c6, 0x1c7, 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c6, 0x1c7, + 0x1c8, 0x1c9, 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1cf, + 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1cf, 0x1cc, 0x1cd, + 0x1ce, 0x1cf, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, 0x1d3, + 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d2, 0x1d3, 0x1d4, 0x1d5, + 0x1d6, 0x1d7, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d6, 0x1d7, + 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, + 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, 0x1dc, 0x1dd, + 0x1de, 0x1df, 0x1de, 0x1df, 0x1ec, 0x1ed, 0x1ee, 0x1ef, + 0x1ec, 0x1ed, 0x1ee, 0x1ef, 0x1eb, 0x1ef, 0x1fc, 0x1fd, + 0x1fe, 0x1ff, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x1fb, 0x1ff, + 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, + 0x000, 0x000, 0x2c4, 0x2c5, 0x2c6, 0x2c7, 0x2c4, 0x2c5, + 0x2c6, 0x2c7, 0x000, 0x000, 0x2c8, 0x2c9, 0x2ca, 0x2cb, + 0x2cc, 0x2cd, 0x2ce, 0x2cf, 0x000, 0x000, 0x2cc, 0x2cd, + 0x2ce, 0x2cf, 0x2cc, 0x2cd, 0x2ce, 0x2cf, 0x000, 0x000, + 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, + 0x000, 0x000, 0x2d4, 0x2d5, 0x2d6, 0x2d7, 0x2d4, 0x2d5, + 0x2d6, 0x2d7, 0x000, 0x000, 0x2d8, 0x2d9, 0x2da, 0x2db, + 0x2dc, 0x2dd, 0x2de, 0x2df, 0x000, 0x000, 0x2dc, 0x2dd, + 0x2de, 0x2df, 0x2dc, 0x2dd, 0x2de, 0x2df, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x3c0, 0x3c1, 0x3c2, 0x3c3, + 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x000, 0x000, 0x3c4, 0x3c5, + 0x3c6, 0x3c7, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x000, 0x000, + 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc, 0x3cd, 0x3ce, 0x3cf, + 0x000, 0x000, 0x3cc, 0x3cd, 0x3ce, 0x3cf, 0x3cc, 0x3cd, + 0x3ce, 0x3cf, 0x000, 0x000, 0x3d0, 0x3d1, 0x3d2, 0x3d3, + 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x000, 0x000, 0x3d4, 0x3d5, + 0x3d6, 0x3d7, 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x000, 0x000, + 0x3d8, 0x3d9, 0x3da, 0x3db, 0x3dc, 0x3dd, 0x3de, 0x3df, + 0x000, 0x000, 0x3dc, 0x3dd, 0x3de, 0x3df, 0x3dc, 0x3dd, + 0x3de, 0x3df, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +constexpr auto encode_dpd(std::uint8_t d0, std::uint8_t d1, std::uint8_t d2) -> std::uint16_t +{ + const auto bcd {(d2 * 100) + (d1 * 10) + d0}; + + BOOST_DECIMAL_ASSERT(bcd >= 0 && bcd < 1000); + return dpd_table[bcd]; +} + +} // namespace decimal +} // namespace boost + +#endif // BOOST_DECIMAL_DPD_CONVERSION_HPP From e04ebd7739ad970201c1f4e2a8d09057585fa8ed Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 14:02:22 -0400 Subject: [PATCH 17/77] Add decoding logic --- include/boost/decimal/dpd_conversion.hpp | 145 +++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 9b5ed9935..0e3a1a076 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -156,6 +156,151 @@ constexpr auto encode_dpd(std::uint8_t d0, std::uint8_t d1, std::uint8_t d2) -> return dpd_table[bcd]; } +constexpr auto decode_dpd(std::uint32_t dpd, std::uint8_t &d2, std::uint8_t &d1, std::uint8_t &d0) -> void { + // DPD decoding logic as per IEEE 754-2008 + std::uint8_t b[10] {}; + for (int i = 0; i < 10; ++i) + { + b[i] = (dpd >> (9 - i)) & 0x1; + } + + std::uint8_t n[12] {}; + + if ((b[0] & b[1] & b[2]) == 0) + { + // All digits are 0-7 + n[0] = b[0]; + n[1] = b[3]; + n[2] = b[6]; + n[3] = b[9]; + n[4] = b[1]; + n[5] = b[4]; + n[6] = b[7]; + n[7] = b[2]; + n[8] = b[5]; + n[9] = b[8]; + n[10] = 0; + n[11] = 0; + } + else + { + // One or more digits are 8 or 9 + const auto d {(b[0] << 2) | (b[1] << 1) | b[2]}; + switch (d) { + case 1: // 001 + n[0] = 1; + n[1] = b[3]; + n[2] = b[6]; + n[3] = b[9]; + n[4] = 1; + n[5] = b[4]; + n[6] = b[7]; + n[7] = 0; + n[8] = b[5]; + n[9] = b[8]; + n[10] = 0; + n[11] = 0; + break; + case 2: // 010 + n[0] = b[3]; + n[1] = 1; + n[2] = b[6]; + n[3] = b[9]; + n[4] = b[4]; + n[5] = 1; + n[6] = b[7]; + n[7] = b[5]; + n[8] = 0; + n[9] = b[8]; + n[10] = 0; + n[11] = 0; + break; + case 3: // 011 + n[0] = 1; + n[1] = 1; + n[2] = b[6]; + n[3] = b[9]; + n[4] = b[4]; + n[5] = b[7]; + n[6] = 0; + n[7] = b[5]; + n[8] = b[8]; + n[9] = 0; + n[10] = 0; + n[11] = 0; + break; + case 4: // 100 + n[0] = b[3]; + n[1] = b[6]; + n[2] = 1; + n[3] = b[9]; + n[4] = b[4]; + n[5] = b[7]; + n[6] = 1; + n[7] = b[5]; + n[8] = b[8]; + n[9] = 0; + n[10] = 0; + n[11] = 0; + break; + case 5: // 101 + n[0] = 1; + n[1] = b[6]; + n[2] = 1; + n[3] = b[9]; + n[4] = b[4]; + n[5] = 1; + n[6] = 1; + n[7] = b[5]; + n[8] = b[8]; + n[9] = 0; + n[10] = 0; + n[11] = 0; + break; + case 6: // 110 + n[0] = b[3]; + n[1] = 1; + n[2] = 1; + n[3] = b[9]; + n[4] = b[4]; + n[5] = b[7]; + n[6] = 1; + n[7] = b[5]; + n[8] = b[8]; + n[9] = 0; + n[10] = 0; + n[11] = 0; + break; + case 7: // 111 + n[0] = 1; + n[1] = 1; + n[2] = 1; + n[3] = b[9]; + n[4] = b[4]; + n[5] = 1; + n[6] = 1; + n[7] = b[5]; + n[8] = b[8]; + n[9] = 0; + n[10] = 0; + n[11] = 0; + break; + default: + // Should not occur + BOOST_DECIMAL_UNREACHABLE; + n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = n[8] = n[9] = n[10] = n[11] = 0; + break; + } + } + + // Reconstruct decimal digits from BCD bits + d2 = static_cast((n[0] << 3) | (n[1] << 2) | (n[2] << 1) | n[3]); + d1 = static_cast((n[4] << 3) | (n[5] << 2) | (n[6] << 1) | n[7]); + d0 = static_cast((n[8] << 3) | (n[9] << 2) | (n[10] << 1) | n[11]); +} + +} // namespace detail + } // namespace decimal } // namespace boost From dfc7765400d4059fb51e826b966f558edf9e5f2b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 14:03:14 -0400 Subject: [PATCH 18/77] Make to_dpd_d32 a friend --- include/boost/decimal/decimal32.hpp | 4 ++++ include/boost/decimal/decimal32_fast.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index febaa9411..be51e55a1 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -218,6 +218,10 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m template friend constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + template + friend BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t); + public: // 3.2.2.1 construct/copy/destroy: constexpr decimal32() noexcept = default; diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 8ac613880..54d280219 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -114,6 +114,10 @@ class decimal32_fast final -> std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_decimal_floating_point_v), bool>; + template + friend BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t); + public: constexpr decimal32_fast() noexcept {} From 6d7301d4a9161b60769dab97d6f00e5820219321 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 16:22:50 -0400 Subject: [PATCH 19/77] Add test set --- test/Jamfile | 1 + test/test_dpd_conversions.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/test_dpd_conversions.cpp diff --git a/test/Jamfile b/test/Jamfile index f4998aa32..0ef7e88eb 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -99,6 +99,7 @@ run test_decimal64_fast_stream.cpp ; run test_decimal64_stream.cpp ; run test_decimal128_basis.cpp ; run test_decimal_quantum.cpp ; +run test_dpd_conversions.cpp ; run test_edges_and_behave.cpp ; run test_edit_members.cpp ; run test_ellint_1.cpp ; diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp new file mode 100644 index 000000000..094927548 --- /dev/null +++ b/test/test_dpd_conversions.cpp @@ -0,0 +1,33 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::decimal; + +template +void test() +{ + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(std::numeric_limits::min(), + std::numeric_limits::max()); + + for (std::size_t i {}; i < 1024; ++i) + { + const T val {dist(rng)}; + const auto bits {to_dpd(val)}; + const T return_val {from_dpd(bits)}; + BOOST_TEST_EQ(val, return_val); + } +} + +int main() +{ + test(); + test(); + + return boost::report_errors(); +} From e792986e88855c3a3502932d57bdbaed7e712913 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 16:22:59 -0400 Subject: [PATCH 20/77] Add to overall decimal project --- include/boost/decimal.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/decimal.hpp b/include/boost/decimal.hpp index eea3b535e..b878eb032 100644 --- a/include/boost/decimal.hpp +++ b/include/boost/decimal.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #if defined(__clang__) && !defined(__GNUC__) # pragma clang diagnostic pop From 694c2d3fb9ba7e817247089bafc261f11a512cb8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 25 Sep 2024 16:23:13 -0400 Subject: [PATCH 21/77] Complete implementation of decoding from DPD --- include/boost/decimal/dpd_conversion.hpp | 289 +++++++++++++---------- 1 file changed, 159 insertions(+), 130 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 0e3a1a076..33ed66288 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -18,7 +18,7 @@ namespace decimal { namespace detail { -// See IEEE 754-2008 tables 3-3 and 3-4 for explanation +// See IEEE 754-2008 table 3-4 for explanation BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint16_t dpd_table[1000] = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, @@ -156,150 +156,179 @@ constexpr auto encode_dpd(std::uint8_t d0, std::uint8_t d1, std::uint8_t d2) -> return dpd_table[bcd]; } -constexpr auto decode_dpd(std::uint32_t dpd, std::uint8_t &d2, std::uint8_t &d1, std::uint8_t &d0) -> void { +constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t &d3, std::uint8_t &d2, std::uint8_t &d1) -> void +{ // DPD decoding logic as per IEEE 754-2008 std::uint8_t b[10] {}; for (int i = 0; i < 10; ++i) { - b[i] = (dpd >> (9 - i)) & 0x1; + b[i] = (dpd_bits >> (9 - i)) & 0x1; } - std::uint8_t n[12] {}; + // See table 3.3 for the flow of decoding + // Values are b6, b7, b8, b3, b4 + // 0XXXX + if (b[6] == 0U) + { + d1 = 4U * b[0] + 2U * b[1] + b[2]; + d2 = 4U * b[3] + 2U * b[4] + b[5]; + d3 = 4U * b[7] + 2U * b[8] + b[9]; + } + // 100XX + else if (b[6] == 1U && b[7] == 0U && b[8] == 0U) + { + d1 = 4U * b[0] + 2U * b[1] + b[2]; + d2 = 4U * b[3] + 2U * b[4] + b[5]; + d3 = 8U + b[9]; + } + // 101XX + else if (b[6] == 1U && b[7] == 0U && b[8] == 1U) + { + d1 = 4U * b[0] + 2U * b[1] + b[2]; + d2 = 8U + b[5]; + d3 = 4U * b[3] + 2U * b[4] + b[9]; + } + // 110XX + else if (b[6] == 1U && b[7] == 1U && b[8] == 0U) + { + d1 = 8U + b[2]; + d2 = 4U * b[3] + 2U * b[4] + b[5]; + d3 = 4U * b[0] + 2U * b[1] + b[9]; + } + // 11100 + else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 0U && b[4] == 0U) + { + d1 = 8U + b[2]; + d2 = 8U + b[5]; + d3 = 4U * b[0] + 2U * b[1] + b[9]; + } + // 11101 + else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 0U && b[4] == 1U) + { + d1 = 8U + b[2]; + d2 = 4U * b[0] + 2U * b[1] + b[5]; + d3 = 8U + b[9]; + } + // 11110 + else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 1U && b[4] == 0U) + { + d1 = 4U * b[0] + 2U * b[1] + b[2]; + d2 = 8U + b[5]; + d3 = 8U + b[9]; + } + // 11111 + else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 1U && b[4] == 1U) + { + d1 = 8U + b[2]; + d2 = 8U + b[5]; + d3 = 8U + b[9]; + } + else + { + BOOST_DECIMAL_UNREACHABLE; + } +} + +} // namespace detail + +template +BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t) +{ + static_assert(std::is_same::value || + std::is_same::value, "The input must be a 32-bit decimal type"); - if ((b[0] & b[1] & b[2]) == 0) + // In the non-finite cases the encodings are the same + // 3.5.2.a and 3.5.2.b + if (!isfinite(val)) { - // All digits are 0-7 - n[0] = b[0]; - n[1] = b[3]; - n[2] = b[6]; - n[3] = b[9]; - n[4] = b[1]; - n[5] = b[4]; - n[6] = b[7]; - n[7] = b[2]; - n[8] = b[5]; - n[9] = b[8]; - n[10] = 0; - n[11] = 0; + return to_bid(val); } + + return 0U; +} + +BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd(decimal32 val) noexcept -> std::uint32_t +{ + return to_dpd_d32(val); +} + +BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t +{ + return to_dpd_d32(val); +} + +template +BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd_d32(std::uint32_t dpd) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + // The bit lengths are the same as used in the standard bid format + const auto sign {(dpd & detail::d32_sign_mask) != 0}; + const auto combination_field_bits {(dpd & detail::d32_combination_field_mask) >> 26U}; + const auto exponent_field_bits {(dpd & detail::d32_exponent_mask) >> 20U}; + const auto significand_bits {(dpd & detail::d32_significand_mask)}; + + // Case 1: 3.5.2.c.1.i + // Combination field bits are 110XX or 11110X + std::uint32_t d0 {}; + std::uint32_t leading_biased_exp_bits {}; + if (combination_field_bits >= 0b11000) + { + // d0 = 8 + G4 + // Must be equal to 8 or 9 + d0 = 8U + (combination_field_bits & 0b00001); + BOOST_DECIMAL_ASSERT(d0 == 8 || d0 == 9); + + // leading exp bits are 2*G2 + G3 + // Must be equal to 0, 1 or 2 + leading_biased_exp_bits = 2U * ((combination_field_bits & 0b00100) >> 2U) + ((combination_field_bits & 0b00010) >> 1U); + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits >= 0U && leading_biased_exp_bits <= 2U); + } + // Case 2: 3.5.2.c.1.ii + // Combination field bits are 0XXXX or 10XXX else { - // One or more digits are 8 or 9 - const auto d {(b[0] << 2) | (b[1] << 1) | b[2]}; - switch (d) { - case 1: // 001 - n[0] = 1; - n[1] = b[3]; - n[2] = b[6]; - n[3] = b[9]; - n[4] = 1; - n[5] = b[4]; - n[6] = b[7]; - n[7] = 0; - n[8] = b[5]; - n[9] = b[8]; - n[10] = 0; - n[11] = 0; - break; - case 2: // 010 - n[0] = b[3]; - n[1] = 1; - n[2] = b[6]; - n[3] = b[9]; - n[4] = b[4]; - n[5] = 1; - n[6] = b[7]; - n[7] = b[5]; - n[8] = 0; - n[9] = b[8]; - n[10] = 0; - n[11] = 0; - break; - case 3: // 011 - n[0] = 1; - n[1] = 1; - n[2] = b[6]; - n[3] = b[9]; - n[4] = b[4]; - n[5] = b[7]; - n[6] = 0; - n[7] = b[5]; - n[8] = b[8]; - n[9] = 0; - n[10] = 0; - n[11] = 0; - break; - case 4: // 100 - n[0] = b[3]; - n[1] = b[6]; - n[2] = 1; - n[3] = b[9]; - n[4] = b[4]; - n[5] = b[7]; - n[6] = 1; - n[7] = b[5]; - n[8] = b[8]; - n[9] = 0; - n[10] = 0; - n[11] = 0; - break; - case 5: // 101 - n[0] = 1; - n[1] = b[6]; - n[2] = 1; - n[3] = b[9]; - n[4] = b[4]; - n[5] = 1; - n[6] = 1; - n[7] = b[5]; - n[8] = b[8]; - n[9] = 0; - n[10] = 0; - n[11] = 0; - break; - case 6: // 110 - n[0] = b[3]; - n[1] = 1; - n[2] = 1; - n[3] = b[9]; - n[4] = b[4]; - n[5] = b[7]; - n[6] = 1; - n[7] = b[5]; - n[8] = b[8]; - n[9] = 0; - n[10] = 0; - n[11] = 0; - break; - case 7: // 111 - n[0] = 1; - n[1] = 1; - n[2] = 1; - n[3] = b[9]; - n[4] = b[4]; - n[5] = 1; - n[6] = 1; - n[7] = b[5]; - n[8] = b[8]; - n[9] = 0; - n[10] = 0; - n[11] = 0; - break; - default: - // Should not occur - BOOST_DECIMAL_UNREACHABLE; - n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = n[8] = n[9] = n[10] = n[11] = 0; - break; - } + // d0 = 4 * G2 + 2 * G3 + G4 + // Must be in the range 0-7 + d0 = 4U * ((combination_field_bits & 0b00100) >> 2U) + 2U * ((combination_field_bits & 0b00010) >> 1U) + combination_field_bits & 0b00001; + BOOST_DECIMAL_ASSERT(d0 >= 0 && d0 <= 7); + + // Leading exp bits are 2 * G0 + G1 + // Must be equal to 0, 1 or 2 + leading_biased_exp_bits = 2U * ((combination_field_bits & 0b10000) >> 4U) + ((combination_field_bits & 0b01000) >> 3U); + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits >= 0U && leading_biased_exp_bits <= 2U); + } + + // Now that we have the bits we can calculate the exponents value + const auto complete_exp {(leading_biased_exp_bits << 6U) + exponent_field_bits}; + const auto exp = complete_exp - detail::bias_v; + + // We can now decode the remainder of the significand to recover the value + std::uint8_t digits[7] {}; + digits[6] = d0; + const auto first_half {significand_bits & 0b1111111111}; + detail::decode_dpd(first_half, digits[2], digits[1], digits[0]); + const auto second_half {(significand_bits & 0b11111111110000000000) >> 10U}; + BOOST_DECIMAL_ASSERT(second_half <= 0b1111111111); + detail::decode_dpd(second_half, digits[5], digits[4], digits[3]); + + // Now we can assemble the significand + std::uint32_t significand {}; + for (std::uint32_t i {}; i < 7U; ++i) + { + significand += digits[i] * detail::pow10(i); } - // Reconstruct decimal digits from BCD bits - d2 = static_cast((n[0] << 3) | (n[1] << 2) | (n[2] << 1) | n[3]); - d1 = static_cast((n[4] << 3) | (n[5] << 2) | (n[6] << 1) | n[7]); - d0 = static_cast((n[8] << 3) | (n[9] << 2) | (n[10] << 1) | n[11]); + return DecimalType{significand, exp, sign}; +} + +template +BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd(std::uint32_t bits) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + return from_dpd_d32(bits); } -} // namespace detail } // namespace decimal } // namespace boost From c11da26c9e8f9ee1639a7386c2360067f9b1e223 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 10:34:43 -0400 Subject: [PATCH 22/77] Implement proper encoding --- include/boost/decimal/dpd_conversion.hpp | 90 +++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 33ed66288..84883503a 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -245,7 +245,95 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept return to_bid(val); } - return 0U; + const auto sign {val.isneg()}; + const auto exp {val.unbiased_exponent()}; + const auto significand {val.full_significand()}; + + std::uint32_t dpd {}; + // Set the sign bit as applicable + if (sign) + { + dpd |= detail::d32_sign_mask; + } + + // Break the significand down into the 7 declets are needed + std::uint8_t d[std::numeric_limits::digits10]; + auto temp_sig {significand}; + for (int i = 7; i >= 0; ++i) + { + d[i] = temp_sig % 10; + temp_sig /= 10; + } + BOOST_DECIMAL_ASSERT(d[0] >= 0 && d[0] <= 9); + + // We now need to capture what the leading two bits of the exponent are, + // since they are stored in the combination field + constexpr std::uint32_t leading_two_exp_bits_mask {0b11000000}; + const auto leading_two_bits {(exp & leading_two_exp_bits_mask) >> 6U}; + BOOST_DECIMAL_ASSERT(leading_two_bits >= 0 && leading_two_bits <= 2); + constexpr std::uint32_t trailing_exp_bits_mask {0b00111111}; + const auto trailing_exp_bits {(exp & trailing_exp_bits_mask)}; + + + std::uint32_t combination_field_bits {}; + // Now based on what the value of d[0] and the leading bits of exp are we can set the value of the combination field + // See 3.5.2.c.1 + // If d0 is 8 or 9 then we follow section i + if (d[0] >= 8) + { + const auto d0_is_nine {d[0] == 9}; + switch (leading_two_bits) + { + case 0U: + combination_field_bits = d0_is_nine ? 0b11001 : 0b11000; + break; + case 1U: + combination_field_bits = d0_is_nine ? 0b11011 : 0b11010; + break; + case 2U: + combination_field_bits = d0_is_nine ? 0b11101 : 0b11100; + break; + default: + BOOST_DECIMAL_UNREACHABLE; + } + } + // If d0 is 0 to 7 then we follow section II + else + { + // In here the value of d[0] = 4*G2 + 2*G3 + G4 + const auto d0_mask {static_cast(d[0])}; + switch (leading_two_bits) + { + case 0U: + // 00XXX + combination_field_bits |= d0_mask; + break; + case 1U: + // 01XXX + combination_field_bits = 0b01000; + combination_field_bits |= d0_mask; + break; + case 2U: + // 10XXX + combination_field_bits = 0b10000; + combination_field_bits |= d0_mask; + break; + default: + BOOST_DECIMAL_UNREACHABLE; + } + } + + // The only thing we have left to compute now is the bit patterns of d[1] - d[6] + const auto declet_1 {static_cast(detail::encode_dpd(d[1], d[2], d[3]))}; + const auto declet_2 {static_cast(detail::encode_dpd(d[4], d[5], d[6]))}; + + // Now we can do final assembly of the number + dpd |= (combination_field_bits << 26U); + dpd |= (trailing_exp_bits << 20U); + dpd |= (declet_1 << 10U); + dpd |= declet_2; + + return dpd; } BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd(decimal32 val) noexcept -> std::uint32_t From 75111512d046ba02c058f40865eae778a370b6e2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 10:40:01 -0400 Subject: [PATCH 23/77] Fix bounds --- include/boost/decimal/dpd_conversion.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 84883503a..0bfa2469c 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -259,7 +259,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept // Break the significand down into the 7 declets are needed std::uint8_t d[std::numeric_limits::digits10]; auto temp_sig {significand}; - for (int i = 7; i >= 0; ++i) + for (int i = 6; i >= 0; --i) { d[i] = temp_sig % 10; temp_sig /= 10; @@ -389,11 +389,11 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd_d32(std::uint32_t dpd) noexcept // Now that we have the bits we can calculate the exponents value const auto complete_exp {(leading_biased_exp_bits << 6U) + exponent_field_bits}; - const auto exp = complete_exp - detail::bias_v; + const auto exp {static_cast(complete_exp) - detail::bias_v}; // We can now decode the remainder of the significand to recover the value std::uint8_t digits[7] {}; - digits[6] = d0; + digits[6] = static_cast(d0); const auto first_half {significand_bits & 0b1111111111}; detail::decode_dpd(first_half, digits[2], digits[1], digits[0]); const auto second_half {(significand_bits & 0b11111111110000000000) >> 10U}; From 4977b6795d4c20337a376fcb016f8c5f79dee93c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 11:31:38 -0400 Subject: [PATCH 24/77] Encode using jump table --- include/boost/decimal/dpd_conversion.hpp | 340 ++++++++++++++--------- 1 file changed, 206 insertions(+), 134 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 0bfa2469c..14f7cde7a 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -18,142 +18,214 @@ namespace decimal { namespace detail { -// See IEEE 754-2008 table 3-4 for explanation -BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint16_t dpd_table[1000] = +// See Table 3.4 +constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> std::uint16_t { - 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, - 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x004, 0x005, - 0x006, 0x007, 0x006, 0x007, 0x008, 0x009, 0x00a, 0x00b, - 0x00c, 0x00d, 0x00e, 0x00f, 0x00a, 0x00b, 0x00c, 0x00d, - 0x00e, 0x00f, 0x00c, 0x00d, 0x00e, 0x00f, 0x00e, 0x00f, - 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, - 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x014, 0x015, - 0x016, 0x017, 0x016, 0x017, 0x018, 0x019, 0x01a, 0x01b, - 0x01c, 0x01d, 0x01e, 0x01f, 0x01a, 0x01b, 0x01c, 0x01d, - 0x01e, 0x01f, 0x01c, 0x01d, 0x01e, 0x01f, 0x01e, 0x01f, - 0x02c, 0x02d, 0x02e, 0x02f, 0x02c, 0x02d, 0x02e, 0x02f, - 0x02b, 0x02f, 0x03c, 0x03d, 0x03e, 0x03f, 0x03c, 0x03d, - 0x03e, 0x03f, 0x03b, 0x03f, 0x040, 0x041, 0x042, 0x043, - 0x044, 0x045, 0x046, 0x047, 0x042, 0x043, 0x044, 0x045, - 0x046, 0x047, 0x044, 0x045, 0x046, 0x047, 0x046, 0x047, - 0x048, 0x049, 0x04a, 0x04b, 0x04c, 0x04d, 0x04e, 0x04f, - 0x04a, 0x04b, 0x04c, 0x04d, 0x04e, 0x04f, 0x04c, 0x04d, - 0x04e, 0x04f, 0x04e, 0x04f, 0x050, 0x051, 0x052, 0x053, - 0x054, 0x055, 0x056, 0x057, 0x052, 0x053, 0x054, 0x055, - 0x056, 0x057, 0x054, 0x055, 0x056, 0x057, 0x056, 0x057, - 0x058, 0x059, 0x05a, 0x05b, 0x05c, 0x05d, 0x05e, 0x05f, - 0x05a, 0x05b, 0x05c, 0x05d, 0x05e, 0x05f, 0x05c, 0x05d, - 0x05e, 0x05f, 0x05e, 0x05f, 0x06c, 0x06d, 0x06e, 0x06f, - 0x06c, 0x06d, 0x06e, 0x06f, 0x06b, 0x06f, 0x07c, 0x07d, - 0x07e, 0x07f, 0x07c, 0x07d, 0x07e, 0x07f, 0x07b, 0x07f, - 0x080, 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, - 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x084, 0x085, - 0x086, 0x087, 0x086, 0x087, 0x088, 0x089, 0x08a, 0x08b, - 0x08c, 0x08d, 0x08e, 0x08f, 0x08a, 0x08b, 0x08c, 0x08d, - 0x08e, 0x08f, 0x08c, 0x08d, 0x08e, 0x08f, 0x08e, 0x08f, - 0x090, 0x091, 0x092, 0x093, 0x094, 0x095, 0x096, 0x097, - 0x092, 0x093, 0x094, 0x095, 0x096, 0x097, 0x094, 0x095, - 0x096, 0x097, 0x096, 0x097, 0x098, 0x099, 0x09a, 0x09b, - 0x09c, 0x09d, 0x09e, 0x09f, 0x09a, 0x09b, 0x09c, 0x09d, - 0x09e, 0x09f, 0x09c, 0x09d, 0x09e, 0x09f, 0x09e, 0x09f, - 0x0ac, 0x0ad, 0x0ae, 0x0af, 0x0ac, 0x0ad, 0x0ae, 0x0af, - 0x0ab, 0x0af, 0x0bc, 0x0bd, 0x0be, 0x0bf, 0x0bc, 0x0bd, - 0x0be, 0x0bf, 0x0bb, 0x0bf, 0x0c0, 0x0c1, 0x0c2, 0x0c3, - 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0c2, 0x0c3, 0x0c4, 0x0c5, - 0x0c6, 0x0c7, 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0c6, 0x0c7, - 0x0c8, 0x0c9, 0x0ca, 0x0cb, 0x0cc, 0x0cd, 0x0ce, 0x0cf, - 0x0ca, 0x0cb, 0x0cc, 0x0cd, 0x0ce, 0x0cf, 0x0cc, 0x0cd, - 0x0ce, 0x0cf, 0x0ce, 0x0cf, 0x0d0, 0x0d1, 0x0d2, 0x0d3, - 0x0d4, 0x0d5, 0x0d6, 0x0d7, 0x0d2, 0x0d3, 0x0d4, 0x0d5, - 0x0d6, 0x0d7, 0x0d4, 0x0d5, 0x0d6, 0x0d7, 0x0d6, 0x0d7, - 0x0d8, 0x0d9, 0x0da, 0x0db, 0x0dc, 0x0dd, 0x0de, 0x0df, - 0x0da, 0x0db, 0x0dc, 0x0dd, 0x0de, 0x0df, 0x0dc, 0x0dd, - 0x0de, 0x0df, 0x0de, 0x0df, 0x0ec, 0x0ed, 0x0ee, 0x0ef, - 0x0ec, 0x0ed, 0x0ee, 0x0ef, 0x0eb, 0x0ef, 0x0fc, 0x0fd, - 0x0fe, 0x0ff, 0x0fc, 0x0fd, 0x0fe, 0x0ff, 0x0fb, 0x0ff, - 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, - 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x104, 0x105, - 0x106, 0x107, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, - 0x10c, 0x10d, 0x10e, 0x10f, 0x10a, 0x10b, 0x10c, 0x10d, - 0x10e, 0x10f, 0x10c, 0x10d, 0x10e, 0x10f, 0x10e, 0x10f, - 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, - 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x114, 0x115, - 0x116, 0x117, 0x116, 0x117, 0x118, 0x119, 0x11a, 0x11b, - 0x11c, 0x11d, 0x11e, 0x11f, 0x11a, 0x11b, 0x11c, 0x11d, - 0x11e, 0x11f, 0x11c, 0x11d, 0x11e, 0x11f, 0x11e, 0x11f, - 0x12c, 0x12d, 0x12e, 0x12f, 0x12c, 0x12d, 0x12e, 0x12f, - 0x12b, 0x12f, 0x13c, 0x13d, 0x13e, 0x13f, 0x13c, 0x13d, - 0x13e, 0x13f, 0x13b, 0x13f, 0x140, 0x141, 0x142, 0x143, - 0x144, 0x145, 0x146, 0x147, 0x142, 0x143, 0x144, 0x145, - 0x146, 0x147, 0x144, 0x145, 0x146, 0x147, 0x146, 0x147, - 0x148, 0x149, 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, - 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, 0x14c, 0x14d, - 0x14e, 0x14f, 0x14e, 0x14f, 0x150, 0x151, 0x152, 0x153, - 0x154, 0x155, 0x156, 0x157, 0x152, 0x153, 0x154, 0x155, - 0x156, 0x157, 0x154, 0x155, 0x156, 0x157, 0x156, 0x157, - 0x158, 0x159, 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, - 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, 0x15c, 0x15d, - 0x15e, 0x15f, 0x15e, 0x15f, 0x16c, 0x16d, 0x16e, 0x16f, - 0x16c, 0x16d, 0x16e, 0x16f, 0x16b, 0x16f, 0x17c, 0x17d, - 0x17e, 0x17f, 0x17c, 0x17d, 0x17e, 0x17f, 0x17b, 0x17f, - 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, - 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, 0x184, 0x185, - 0x186, 0x187, 0x186, 0x187, 0x188, 0x189, 0x18a, 0x18b, - 0x18c, 0x18d, 0x18e, 0x18f, 0x18a, 0x18b, 0x18c, 0x18d, - 0x18e, 0x18f, 0x18c, 0x18d, 0x18e, 0x18f, 0x18e, 0x18f, - 0x190, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, - 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x194, 0x195, - 0x196, 0x197, 0x196, 0x197, 0x198, 0x199, 0x19a, 0x19b, - 0x19c, 0x19d, 0x19e, 0x19f, 0x19a, 0x19b, 0x19c, 0x19d, - 0x19e, 0x19f, 0x19c, 0x19d, 0x19e, 0x19f, 0x19e, 0x19f, - 0x1ac, 0x1ad, 0x1ae, 0x1af, 0x1ac, 0x1ad, 0x1ae, 0x1af, - 0x1ab, 0x1af, 0x1bc, 0x1bd, 0x1be, 0x1bf, 0x1bc, 0x1bd, - 0x1be, 0x1bf, 0x1bb, 0x1bf, 0x1c0, 0x1c1, 0x1c2, 0x1c3, - 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c2, 0x1c3, 0x1c4, 0x1c5, - 0x1c6, 0x1c7, 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c6, 0x1c7, - 0x1c8, 0x1c9, 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1cf, - 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1cf, 0x1cc, 0x1cd, - 0x1ce, 0x1cf, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, 0x1d3, - 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d2, 0x1d3, 0x1d4, 0x1d5, - 0x1d6, 0x1d7, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d6, 0x1d7, - 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, - 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, 0x1dc, 0x1dd, - 0x1de, 0x1df, 0x1de, 0x1df, 0x1ec, 0x1ed, 0x1ee, 0x1ef, - 0x1ec, 0x1ed, 0x1ee, 0x1ef, 0x1eb, 0x1ef, 0x1fc, 0x1fd, - 0x1fe, 0x1ff, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x1fb, 0x1ff, - 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, - 0x000, 0x000, 0x2c4, 0x2c5, 0x2c6, 0x2c7, 0x2c4, 0x2c5, - 0x2c6, 0x2c7, 0x000, 0x000, 0x2c8, 0x2c9, 0x2ca, 0x2cb, - 0x2cc, 0x2cd, 0x2ce, 0x2cf, 0x000, 0x000, 0x2cc, 0x2cd, - 0x2ce, 0x2cf, 0x2cc, 0x2cd, 0x2ce, 0x2cf, 0x000, 0x000, - 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, - 0x000, 0x000, 0x2d4, 0x2d5, 0x2d6, 0x2d7, 0x2d4, 0x2d5, - 0x2d6, 0x2d7, 0x000, 0x000, 0x2d8, 0x2d9, 0x2da, 0x2db, - 0x2dc, 0x2dd, 0x2de, 0x2df, 0x000, 0x000, 0x2dc, 0x2dd, - 0x2de, 0x2df, 0x2dc, 0x2dd, 0x2de, 0x2df, 0x000, 0x000, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x000, 0x000, 0x000, 0x000, 0x3c0, 0x3c1, 0x3c2, 0x3c3, - 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x000, 0x000, 0x3c4, 0x3c5, - 0x3c6, 0x3c7, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x000, 0x000, - 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc, 0x3cd, 0x3ce, 0x3cf, - 0x000, 0x000, 0x3cc, 0x3cd, 0x3ce, 0x3cf, 0x3cc, 0x3cd, - 0x3ce, 0x3cf, 0x000, 0x000, 0x3d0, 0x3d1, 0x3d2, 0x3d3, - 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x000, 0x000, 0x3d4, 0x3d5, - 0x3d6, 0x3d7, 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x000, 0x000, - 0x3d8, 0x3d9, 0x3da, 0x3db, 0x3dc, 0x3dd, 0x3de, 0x3df, - 0x000, 0x000, 0x3dc, 0x3dd, 0x3de, 0x3df, 0x3dc, 0x3dd, - 0x3de, 0x3df, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 -}; - -constexpr auto encode_dpd(std::uint8_t d0, std::uint8_t d1, std::uint8_t d2) -> std::uint16_t -{ - const auto bcd {(d2 * 100) + (d1 * 10) + d0}; + constexpr std::uint8_t b3_mask {0b0001}; + constexpr std::uint8_t b2_mask {0b0010}; + constexpr std::uint8_t b1_mask {0b0100}; + constexpr std::uint8_t b0_mask {0b1000}; + + const std::uint8_t b1[4] = { + static_cast((d1 & b0_mask) >> 3U), + static_cast((d1 & b1_mask) >> 2U), + static_cast((d2 & b2_mask) >> 1U), + static_cast((d3 & b3_mask)) + }; + + const std::uint8_t b2[4] = { + static_cast((d2 & b0_mask) >> 3U), + static_cast((d2 & b1_mask) >> 2U), + static_cast((d2 & b2_mask) >> 1U), + static_cast((d2 & b3_mask)) + }; + + const std::uint8_t b3[4] = { + static_cast((d3 & b0_mask) >> 3U), + static_cast((d3 & b1_mask) >> 2U), + static_cast((d3 & b2_mask) >> 1U), + static_cast((d3 & b3_mask)) + }; + + std::uint8_t result_b[10] {}; + + const auto table_val {(b1[0] << 2) + (b2[0] << 1) + b3[0]}; + + // Now that we have dissected the bits of d1, d2, and d3 we can use the lookup table from 3.4 to generate + // all possible combinations + switch (table_val) + { + case 0b000: + // b0, b1, b2 + result_b[0] = b1[1]; + result_b[1] = b1[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = b2[1]; + result_b[4] = b2[2]; + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(0); + + // b7, b8, b9 + result_b[7] = b3[1]; + result_b[8] = b3[2]; + result_b[9] = b3[3]; + break; + + case 0b001: + // b0, b1, b2 + result_b[0] = b1[1]; + result_b[1] = b1[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = b2[1]; + result_b[4] = b2[2]; + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[9] = b3[3]; + break; + + case 0b010: + // b0, b1, b2 + result_b[0] = b1[1]; + result_b[1] = b1[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = b3[1]; + result_b[4] = b3[2]; + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[7] = static_cast(0); + result_b[8] = static_cast(1); + result_b[9] = b3[3]; + break; + + case 0b011: + // b0, b1, b2 + result_b[0] = b1[1]; + result_b[1] = b1[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = static_cast(1); + result_b[4] = static_cast(0); + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[7] = static_cast(1); + result_b[8] = static_cast(1); + result_b[9] = b3[3]; + break; + + case 0b100: + // b0, b1, b2 + result_b[0] = b3[1]; + result_b[1] = b3[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = b2[1]; + result_b[4] = b2[2]; + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[7] = static_cast(1); + result_b[8] = static_cast(0); + result_b[9] = b3[3]; + break; + + case 0b101: + // b0, b1, b2 + result_b[0] = b2[1]; + result_b[1] = b2[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = static_cast(0); + result_b[4] = static_cast(1); + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[7] = static_cast(1); + result_b[8] = static_cast(1); + result_b[9] = b3[3]; + break; + + case 0b110: + // b0, b1, b2 + result_b[0] = b3[1]; + result_b[1] = b3[2]; + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = static_cast(0); + result_b[4] = static_cast(0); + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[7] = static_cast(1); + result_b[8] = static_cast(1); + result_b[9] = b3[3]; + break; + + case 0b111: + // b0, b1, b2 + result_b[0] = static_cast(0); + result_b[1] = static_cast(0); + result_b[2] = b1[3]; + + // b3, b4, b5 + result_b[3] = static_cast(1); + result_b[4] = static_cast(1); + result_b[5] = b2[3]; + + // b6 + result_b[6] = static_cast(1); + + // b7, b8, b9 + result_b[7] = static_cast(1); + result_b[8] = static_cast(1); + result_b[9] = b3[3]; + break; + + default: + BOOST_DECIMAL_UNREACHABLE; + } - BOOST_DECIMAL_ASSERT(bcd >= 0 && bcd < 1000); - return dpd_table[bcd]; + // Now that we have the bit pattern of the result we need to write it into uint16_t and return the result + std::uint16_t result {}; + + for (std::uint16_t i {}; i < 10U; ++i) + { + result |= (result_b[i] << i); + } + + return result; } constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t &d3, std::uint8_t &d2, std::uint8_t &d1) -> void From 3657a3671470700e89eb7643c85e05413b6fd686 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 11:34:48 -0400 Subject: [PATCH 25/77] Add assertions --- include/boost/decimal/dpd_conversion.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 14f7cde7a..445136ca6 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -32,6 +32,7 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> static_cast((d2 & b2_mask) >> 1U), static_cast((d3 & b3_mask)) }; + BOOST_DECIMAL_ASSERT(b1[0] <= 1U && b1[1] <= 1U && b1[2] <= 1U && b1[3] <= 1); const std::uint8_t b2[4] = { static_cast((d2 & b0_mask) >> 3U), @@ -39,6 +40,7 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> static_cast((d2 & b2_mask) >> 1U), static_cast((d2 & b3_mask)) }; + BOOST_DECIMAL_ASSERT(b2[0] <= 1U && b2[1] <= 1U && b2[2] <= 1U && b2[3] <= 1); const std::uint8_t b3[4] = { static_cast((d3 & b0_mask) >> 3U), @@ -46,10 +48,12 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> static_cast((d3 & b2_mask) >> 1U), static_cast((d3 & b3_mask)) }; + BOOST_DECIMAL_ASSERT(b3[0] <= 1U && b3[1] <= 1U && b3[2] <= 1U && b3[3] <= 1); std::uint8_t result_b[10] {}; const auto table_val {(b1[0] << 2) + (b2[0] << 1) + b3[0]}; + BOOST_DECIMAL_ASSERT(table_val >= 0b000 && table_val <= 0b111); // Now that we have dissected the bits of d1, d2, and d3 we can use the lookup table from 3.4 to generate // all possible combinations @@ -224,7 +228,7 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> { result |= (result_b[i] << i); } - + return result; } From 4ace3ea6089967a3568c77ed4e0ed70b7c1f31d9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 13:14:08 -0400 Subject: [PATCH 26/77] Validate encoding path --- include/boost/decimal/dpd_conversion.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 445136ca6..e6084582a 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -29,8 +29,8 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> const std::uint8_t b1[4] = { static_cast((d1 & b0_mask) >> 3U), static_cast((d1 & b1_mask) >> 2U), - static_cast((d2 & b2_mask) >> 1U), - static_cast((d3 & b3_mask)) + static_cast((d1 & b2_mask) >> 1U), + static_cast((d1 & b3_mask)) }; BOOST_DECIMAL_ASSERT(b1[0] <= 1U && b1[1] <= 1U && b1[2] <= 1U && b1[3] <= 1); @@ -226,7 +226,7 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> for (std::uint16_t i {}; i < 10U; ++i) { - result |= (result_b[i] << i); + result |= (result_b[i] << (9 - i)); } return result; @@ -238,7 +238,7 @@ constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t &d3, std::uint8_t std::uint8_t b[10] {}; for (int i = 0; i < 10; ++i) { - b[i] = (dpd_bits >> (9 - i)) & 0x1; + b[i] = (dpd_bits >> (9 - i)) & 0b1; } // See table 3.3 for the flow of decoding @@ -333,7 +333,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept } // Break the significand down into the 7 declets are needed - std::uint8_t d[std::numeric_limits::digits10]; + std::uint8_t d[std::numeric_limits::digits10] {}; auto temp_sig {significand}; for (int i = 6; i >= 0; --i) { @@ -341,6 +341,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept temp_sig /= 10; } BOOST_DECIMAL_ASSERT(d[0] >= 0 && d[0] <= 9); + BOOST_DECIMAL_ASSERT(temp_sig == 0); // We now need to capture what the leading two bits of the exponent are, // since they are stored in the combination field From 437e6135c8a3547130e3e2eb3b92524921ee02e9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 14:03:22 -0400 Subject: [PATCH 27/77] Fix endianess of encoding --- include/boost/decimal/dpd_conversion.hpp | 18 +++++++++--------- test/test_dpd_conversions.cpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index e6084582a..4375590fc 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -455,12 +455,12 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd_d32(std::uint32_t dpd) noexcept { // d0 = 4 * G2 + 2 * G3 + G4 // Must be in the range 0-7 - d0 = 4U * ((combination_field_bits & 0b00100) >> 2U) + 2U * ((combination_field_bits & 0b00010) >> 1U) + combination_field_bits & 0b00001; + d0 = combination_field_bits & 0b00111; BOOST_DECIMAL_ASSERT(d0 >= 0 && d0 <= 7); // Leading exp bits are 2 * G0 + G1 // Must be equal to 0, 1 or 2 - leading_biased_exp_bits = 2U * ((combination_field_bits & 0b10000) >> 4U) + ((combination_field_bits & 0b01000) >> 3U); + leading_biased_exp_bits = (combination_field_bits & 0b11000) >> 3U; BOOST_DECIMAL_ASSERT(leading_biased_exp_bits >= 0U && leading_biased_exp_bits <= 2U); } @@ -470,18 +470,18 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd_d32(std::uint32_t dpd) noexcept // We can now decode the remainder of the significand to recover the value std::uint8_t digits[7] {}; - digits[6] = static_cast(d0); - const auto first_half {significand_bits & 0b1111111111}; - detail::decode_dpd(first_half, digits[2], digits[1], digits[0]); - const auto second_half {(significand_bits & 0b11111111110000000000) >> 10U}; - BOOST_DECIMAL_ASSERT(second_half <= 0b1111111111); - detail::decode_dpd(second_half, digits[5], digits[4], digits[3]); + digits[0] = static_cast(d0); + const auto significand_low {significand_bits & 0b1111111111}; + detail::decode_dpd(significand_low, digits[6], digits[5], digits[4]); + const auto significand_high {(significand_bits & 0b11111111110000000000) >> 10U}; + BOOST_DECIMAL_ASSERT(significand_high <= 0b1111111111); + detail::decode_dpd(significand_high, digits[3], digits[2], digits[1]); // Now we can assemble the significand std::uint32_t significand {}; for (std::uint32_t i {}; i < 7U; ++i) { - significand += digits[i] * detail::pow10(i); + significand += digits[i] * detail::pow10(6 - i); } return DecimalType{significand, exp, sign}; diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp index 094927548..70a4107ef 100644 --- a/test/test_dpd_conversions.cpp +++ b/test/test_dpd_conversions.cpp @@ -26,7 +26,7 @@ void test() int main() { - test(); + // test(); test(); return boost::report_errors(); From 1454d8837707f3df03cda6f55d4ca8d4a1009abf Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 14:14:06 -0400 Subject: [PATCH 28/77] Re-enable regular dec32 testing --- test/test_dpd_conversions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp index 70a4107ef..094927548 100644 --- a/test/test_dpd_conversions.cpp +++ b/test/test_dpd_conversions.cpp @@ -26,7 +26,7 @@ void test() int main() { - // test(); + test(); test(); return boost::report_errors(); From 74383dc4bda6976080606700650e0c97a6236c51 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 14:39:52 -0400 Subject: [PATCH 29/77] C++20 is not required --- include/boost/decimal/decimal32.hpp | 2 +- include/boost/decimal/decimal32_fast.hpp | 2 +- include/boost/decimal/dpd_conversion.hpp | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index be51e55a1..41be4a351 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -219,7 +219,7 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m friend constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; template - friend BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept + friend constexpr auto to_dpd_d32(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t); public: diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 54d280219..48f5881bb 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -115,7 +115,7 @@ class decimal32_fast final detail::is_decimal_floating_point_v), bool>; template - friend BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept + friend constexpr auto to_dpd_d32(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t); public: diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 4375590fc..d9cc45c74 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -308,7 +308,7 @@ constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t &d3, std::uint8_t } // namespace detail template -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept +constexpr auto to_dpd_d32(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t) { static_assert(std::is_same::value || @@ -413,18 +413,18 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd_d32(DecimalType val) noexcept return dpd; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd(decimal32 val) noexcept -> std::uint32_t +constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t { return to_dpd_d32(val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t +constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t { return to_dpd_d32(val); } template -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd_d32(std::uint32_t dpd) noexcept +constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { // The bit lengths are the same as used in the standard bid format @@ -488,7 +488,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd_d32(std::uint32_t dpd) noexcept } template -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_dpd(std::uint32_t bits) noexcept +constexpr auto from_dpd(std::uint32_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { return from_dpd_d32(bits); From 6e50c82c27c5b2bf84533b837d350546bfe8d4f5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 14:40:01 -0400 Subject: [PATCH 30/77] Update docs --- doc/decimal/conversions.adoc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 6a199b7e7..73d57454d 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -5,11 +5,12 @@ https://www.boost.org/LICENSE_1_0.txt //// [#conversions] -= Fast Type Conversions += Bit Conversions :idprefix: conversions_ -Since we have non-IEEE 754 compliant types we offer a set of functions that allow their conversion to and from the IEEE 754 compliant BID layout. -These functions allow lossless conversion with more compact storage. +IEEE 754 specifies two different encodings for decimal floating point types: Binary Integer Significand Field (BID), and Densely Packed Decimal Significand Field (DPD). +Internally this library is implemented in the BID format for the IEEE-754 compliant types. +Should the user want to capture the bit format in BID or convert to DPD we offer a family of conversion functions: `to_bid`, `from_bid`, `to_dpd`, and `from_dpd` that allow conversion to or from the bit strings regardless of encoding. [source, c++] ---- @@ -26,6 +27,8 @@ struct uint128 } // namespace detail +// ----- BID Conversions ----- + BOOST_DECIMAL_CXX20_CONSTEXPR std::uint32_t to_bid_d32(decimal32 val) noexcept; BOOST_DECIMAL_CXX20_CONSTEXPR std::uint32_t to_bid_d32f(decimal32_fast val) noexcept; @@ -48,6 +51,18 @@ BOOST_DECIMAL_CXX20_CONSTEXPR T from_bid(std::uint64_t bits) noexcept; template BOOST_DECIMAL_CXX20_CONSTEXPR T from_bid(detail::uint128 bits) noexcept; +// ----- DPD Conversions ----- + +constexpr std::uint32_t to_dpd_d32(decimal32 val) noexcept; + +constexpr std::uint32_t to_dpd_d32f(decimal32_fast val) noexcept; + +template +constexpr auto to_dpd(T val) noexcept; + +template +constexpr T from_dpd(std::uint32_t bits) noexcept; + } // namespace decimal } // namespace boost ---- From f8dc430c6b9a2b62abdb0c1b2c90b5a8f1d65e2a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 14:43:56 -0400 Subject: [PATCH 31/77] Add testing of non-finite values --- test/test_dpd_conversions.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp index 094927548..d85ccddd8 100644 --- a/test/test_dpd_conversions.cpp +++ b/test/test_dpd_conversions.cpp @@ -8,6 +8,13 @@ using namespace boost::decimal; +template +T roundtrip(T val) +{ + const auto bits {to_dpd(val)}; + return from_dpd(bits); +} + template void test() { @@ -18,10 +25,17 @@ void test() for (std::size_t i {}; i < 1024; ++i) { const T val {dist(rng)}; - const auto bits {to_dpd(val)}; - const T return_val {from_dpd(bits)}; + const T return_val {roundtrip(val)}; BOOST_TEST_EQ(val, return_val); } + + // Non-finite values + BOOST_TEST(isinf(roundtrip(std::numeric_limits::infinity()))); + BOOST_TEST(isinf(roundtrip(-std::numeric_limits::infinity()))); + BOOST_TEST(isnan(roundtrip(std::numeric_limits::quiet_NaN()))); + BOOST_TEST(isnan(roundtrip(-std::numeric_limits::quiet_NaN()))); + BOOST_TEST(isnan(roundtrip(std::numeric_limits::signaling_NaN()))); + BOOST_TEST(isnan(roundtrip(-std::numeric_limits::signaling_NaN()))); } int main() From e9b0200fa0ce3e5889c0f790ddce73f607fbebc5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 15:07:03 -0400 Subject: [PATCH 32/77] Add handling of non-finite numbers in from_dpd --- include/boost/decimal/dpd_conversion.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index d9cc45c74..14c41e264 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -11,6 +11,7 @@ #ifndef BOOST_DECIMAL_BUILD_MODULE #include +#include #endif namespace boost { @@ -427,6 +428,24 @@ template constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { + // First we check for non-finite values + // Since they are in the same initial format as BID it's easy to check with our existing masks + if ((dpd & detail::d32_inf_mask) == detail::d32_inf_mask) + { + if ((dpd & detail::d32_snan_mask) == detail::d32_snan_mask) + { + return std::numeric_limits::signaling_NaN(); + } + else if ((dpd & detail::d32_nan_mask) == detail::d32_nan_mask) + { + return std::numeric_limits::quiet_NaN(); + } + else + { + return std::numeric_limits::infinity(); + } + } + // The bit lengths are the same as used in the standard bid format const auto sign {(dpd & detail::d32_sign_mask) != 0}; const auto combination_field_bits {(dpd & detail::d32_combination_field_mask) >> 26U}; From e389dbb835267ca77b91998bc8d2c361fdbbbe9b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 15:35:57 -0400 Subject: [PATCH 33/77] Fix conversion errors --- include/boost/decimal/dpd_conversion.hpp | 62 ++++++++++++------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 14c41e264..6f3ce5de6 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -233,13 +233,13 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> return result; } -constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t &d3, std::uint8_t &d2, std::uint8_t &d1) -> void +constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t& d3, std::uint8_t& d2, std::uint8_t& d1) -> void { // DPD decoding logic as per IEEE 754-2008 std::uint8_t b[10] {}; for (int i = 0; i < 10; ++i) { - b[i] = (dpd_bits >> (9 - i)) & 0b1; + b[i] = static_cast((dpd_bits >> (9 - i)) & 0b1); } // See table 3.3 for the flow of decoding @@ -247,58 +247,58 @@ constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t &d3, std::uint8_t // 0XXXX if (b[6] == 0U) { - d1 = 4U * b[0] + 2U * b[1] + b[2]; - d2 = 4U * b[3] + 2U * b[4] + b[5]; - d3 = 4U * b[7] + 2U * b[8] + b[9]; + d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); + d2 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[5]); + d3 = static_cast((b[7] << 2U) + (b[8] << 1U) + b[9]); } // 100XX else if (b[6] == 1U && b[7] == 0U && b[8] == 0U) { - d1 = 4U * b[0] + 2U * b[1] + b[2]; - d2 = 4U * b[3] + 2U * b[4] + b[5]; - d3 = 8U + b[9]; + d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); + d2 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[5]); + d3 = static_cast(8) + b[9]; } // 101XX else if (b[6] == 1U && b[7] == 0U && b[8] == 1U) { - d1 = 4U * b[0] + 2U * b[1] + b[2]; - d2 = 8U + b[5]; - d3 = 4U * b[3] + 2U * b[4] + b[9]; + d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); + d2 = static_cast(8) + b[5]; + d3 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[9]); } // 110XX else if (b[6] == 1U && b[7] == 1U && b[8] == 0U) { - d1 = 8U + b[2]; - d2 = 4U * b[3] + 2U * b[4] + b[5]; - d3 = 4U * b[0] + 2U * b[1] + b[9]; + d1 = static_cast(8) + b[2]; + d2 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[5]); + d3 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[9]); } // 11100 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 0U && b[4] == 0U) { - d1 = 8U + b[2]; - d2 = 8U + b[5]; - d3 = 4U * b[0] + 2U * b[1] + b[9]; + d1 = static_cast(8) + b[2]; + d2 = static_cast(8) + b[5]; + d3 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[9]); } // 11101 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 0U && b[4] == 1U) { - d1 = 8U + b[2]; - d2 = 4U * b[0] + 2U * b[1] + b[5]; - d3 = 8U + b[9]; + d1 = static_cast(8) + b[2]; + d2 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[5]); + d3 = static_cast(8) + b[9]; } // 11110 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 1U && b[4] == 0U) { - d1 = 4U * b[0] + 2U * b[1] + b[2]; - d2 = 8U + b[5]; - d3 = 8U + b[9]; + d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); + d2 = static_cast(8) + b[5]; + d3 = static_cast(8) + b[9]; } // 11111 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 1U && b[4] == 1U) { - d1 = 8U + b[2]; - d2 = 8U + b[5]; - d3 = 8U + b[9]; + d1 = static_cast(8) + b[2]; + d2 = static_cast(8) + b[5]; + d3 = static_cast(8) + b[9]; } else { @@ -338,8 +338,8 @@ constexpr auto to_dpd_d32(DecimalType val) noexcept auto temp_sig {significand}; for (int i = 6; i >= 0; --i) { - d[i] = temp_sig % 10; - temp_sig /= 10; + d[i] = static_cast(temp_sig % 10U); + temp_sig /= 10U; } BOOST_DECIMAL_ASSERT(d[0] >= 0 && d[0] <= 9); BOOST_DECIMAL_ASSERT(temp_sig == 0); @@ -466,7 +466,7 @@ constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept // leading exp bits are 2*G2 + G3 // Must be equal to 0, 1 or 2 leading_biased_exp_bits = 2U * ((combination_field_bits & 0b00100) >> 2U) + ((combination_field_bits & 0b00010) >> 1U); - BOOST_DECIMAL_ASSERT(leading_biased_exp_bits >= 0U && leading_biased_exp_bits <= 2U); + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U); } // Case 2: 3.5.2.c.1.ii // Combination field bits are 0XXXX or 10XXX @@ -475,12 +475,12 @@ constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept // d0 = 4 * G2 + 2 * G3 + G4 // Must be in the range 0-7 d0 = combination_field_bits & 0b00111; - BOOST_DECIMAL_ASSERT(d0 >= 0 && d0 <= 7); + BOOST_DECIMAL_ASSERT(d0 <= 7); // Leading exp bits are 2 * G0 + G1 // Must be equal to 0, 1 or 2 leading_biased_exp_bits = (combination_field_bits & 0b11000) >> 3U; - BOOST_DECIMAL_ASSERT(leading_biased_exp_bits >= 0U && leading_biased_exp_bits <= 2U); + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U); } // Now that we have the bits we can calculate the exponents value From b930cd8ccd073492d207ede094ddbce7d9f2231e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Sep 2024 16:46:11 -0400 Subject: [PATCH 34/77] Fix more conversion warnings --- include/boost/decimal/dpd_conversion.hpp | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 6f3ce5de6..86faf0e1d 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -227,7 +227,7 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> for (std::uint16_t i {}; i < 10U; ++i) { - result |= (result_b[i] << (9 - i)); + result |= static_cast(result_b[i] << (9 - i)); } return result; @@ -256,49 +256,49 @@ constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t& d3, std::uint8_t { d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); d2 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[5]); - d3 = static_cast(8) + b[9]; + d3 = static_cast(8U + b[9]); } // 101XX else if (b[6] == 1U && b[7] == 0U && b[8] == 1U) { d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); - d2 = static_cast(8) + b[5]; + d2 = static_cast(8U + b[5]); d3 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[9]); } // 110XX else if (b[6] == 1U && b[7] == 1U && b[8] == 0U) { - d1 = static_cast(8) + b[2]; + d1 = static_cast(8U + b[2]); d2 = static_cast((b[3] << 2U) + (b[4] << 1U) + b[5]); d3 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[9]); } // 11100 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 0U && b[4] == 0U) { - d1 = static_cast(8) + b[2]; - d2 = static_cast(8) + b[5]; + d1 = static_cast(8U + b[2]); + d2 = static_cast(8U + b[5]); d3 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[9]); } // 11101 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 0U && b[4] == 1U) { - d1 = static_cast(8) + b[2]; + d1 = static_cast(8U + b[2]); d2 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[5]); - d3 = static_cast(8) + b[9]; + d3 = static_cast(8U + b[9]); } // 11110 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 1U && b[4] == 0U) { d1 = static_cast((b[0] << 2U) + (b[1] << 1U) + b[2]); - d2 = static_cast(8) + b[5]; - d3 = static_cast(8) + b[9]; + d2 = static_cast(8U + b[5]); + d3 = static_cast(8U + b[9]); } // 11111 else if (b[6] == 1U && b[7] == 1U && b[8] == 1U && b[3] == 1U && b[4] == 1U) { - d1 = static_cast(8) + b[2]; - d2 = static_cast(8) + b[5]; - d3 = static_cast(8) + b[9]; + d1 = static_cast(8U + b[2]); + d2 = static_cast(8U + b[5]); + d3 = static_cast(8U + b[9]); } else { From 4d595b8170e274359214bba3653aa9564b84d19a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 09:20:32 -0400 Subject: [PATCH 35/77] Add LCOV exclude markers --- include/boost/decimal/dpd_conversion.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 86faf0e1d..75335a012 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -217,9 +217,10 @@ constexpr auto encode_dpd(std::uint8_t d1, std::uint8_t d2, std::uint8_t d3) -> result_b[8] = static_cast(1); result_b[9] = b3[3]; break; - + // LCOV_EXCL_START default: BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP } // Now that we have the bit pattern of the result we need to write it into uint16_t and return the result @@ -300,10 +301,12 @@ constexpr auto decode_dpd(std::uint32_t dpd_bits, std::uint8_t& d3, std::uint8_t d2 = static_cast(8U + b[5]); d3 = static_cast(8U + b[9]); } + // LCOV_EXCL_START else { BOOST_DECIMAL_UNREACHABLE; } + // LCOV_EXCL_STOP } } // namespace detail @@ -371,8 +374,10 @@ constexpr auto to_dpd_d32(DecimalType val) noexcept case 2U: combination_field_bits = d0_is_nine ? 0b11101 : 0b11100; break; + // LCOV_EXCL_START default: BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP } } // If d0 is 0 to 7 then we follow section II @@ -396,8 +401,10 @@ constexpr auto to_dpd_d32(DecimalType val) noexcept combination_field_bits = 0b10000; combination_field_bits |= d0_mask; break; + // LCOV_EXCL_START default: BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP } } From db3e924014836ad00a48a9c73f596bb03695871e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 09:23:24 -0400 Subject: [PATCH 36/77] Test larger range of values --- test/test_dpd_conversions.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp index d85ccddd8..b0d64520d 100644 --- a/test/test_dpd_conversions.cpp +++ b/test/test_dpd_conversions.cpp @@ -38,10 +38,28 @@ void test() BOOST_TEST(isnan(roundtrip(-std::numeric_limits::signaling_NaN()))); } +template +void test_float_range() +{ + std::mt19937_64 rng(42); + std::uniform_real_distribution dist(std::numeric_limits::min(), + std::numeric_limits::max()); + + for (std::size_t i {}; i < 1024; ++i) + { + const T val {dist(rng)}; + const T return_val {roundtrip(val)}; + BOOST_TEST_EQ(val, return_val); + } +} + int main() { test(); test(); + test_float_range(); + test_float_range(); + return boost::report_errors(); } From 56a2643399bdc4902f4e705384f2e941082279e9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 09:45:22 -0400 Subject: [PATCH 37/77] Simplify d32 bid_conversions --- doc/decimal/conversions.adoc | 4 ++-- include/boost/decimal/bid_conversion.hpp | 10 ++++------ include/boost/decimal/decimal32.hpp | 4 ++++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 73d57454d..89d6c8a52 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -29,7 +29,7 @@ struct uint128 // ----- BID Conversions ----- -BOOST_DECIMAL_CXX20_CONSTEXPR std::uint32_t to_bid_d32(decimal32 val) noexcept; +constexpr std::uint32_t to_bid_d32(decimal32 val) noexcept; BOOST_DECIMAL_CXX20_CONSTEXPR std::uint32_t to_bid_d32f(decimal32_fast val) noexcept; @@ -43,7 +43,7 @@ template BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(T val) noexcept; template -BOOST_DECIMAL_CXX20_CONSTEXPR T from_bid(std::uint32_t bits) noexcept; +constexpr T from_bid(std::uint32_t bits) noexcept; template BOOST_DECIMAL_CXX20_CONSTEXPR T from_bid(std::uint64_t bits) noexcept; diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index cb84317b1..cd4d75bd2 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -20,16 +20,14 @@ namespace decimal { # pragma GCC diagnostic ignored "-Wconversion" #endif -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d32(decimal32 val) noexcept -> std::uint32_t +constexpr auto to_bid_d32(decimal32 val) noexcept -> std::uint32_t { - const auto bits {detail::bit_cast(val)}; - return bits; + return val.bits_; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid_d32(std::uint32_t bits) noexcept -> decimal32 +constexpr auto from_bid_d32(std::uint32_t bits) noexcept -> decimal32 { - const auto val {detail::bit_cast(bits)}; - return val; + return from_bits(bits); } BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d32f(decimal32_fast val) noexcept -> std::uint32_t diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 41be4a351..26370367f 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -218,6 +218,10 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m template friend constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + friend constexpr auto to_bid_d32(decimal32 val) noexcept -> std::uint32_t; + + friend constexpr auto from_bid_d32(std::uint32_t bits) noexcept -> decimal32; + template friend constexpr auto to_dpd_d32(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint32_t); From 8dde585e1be777c616cd2202392e2c6c3c11cc05 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 09:49:32 -0400 Subject: [PATCH 38/77] Simplify and document d32_fast bid conversions --- doc/decimal/conversions.adoc | 6 +++++- include/boost/decimal/bid_conversion.hpp | 9 ++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 89d6c8a52..726d4e1af 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -31,7 +31,11 @@ struct uint128 constexpr std::uint32_t to_bid_d32(decimal32 val) noexcept; -BOOST_DECIMAL_CXX20_CONSTEXPR std::uint32_t to_bid_d32f(decimal32_fast val) noexcept; +constexpr decimal32 from_bid_d32(std::uint32_t bits) noexcept; + +constexpr std::uint32_t to_bid_d32f(decimal32_fast val) noexcept; + +constexpr decimal32_fast from_bid_d32f(std::uint32_t bits) noexcept; BOOST_DECIMAL_CXX20_CONSTEXPR std::uint64_t to_bid_d64(decimal64 val) noexcept; diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index cd4d75bd2..0123d69f8 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -30,16 +30,15 @@ constexpr auto from_bid_d32(std::uint32_t bits) noexcept -> decimal32 return from_bits(bits); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d32f(decimal32_fast val) noexcept -> std::uint32_t +constexpr auto to_bid_d32f(decimal32_fast val) noexcept -> std::uint32_t { const decimal32 compliant_val {val}; - const auto bits {detail::bit_cast(compliant_val)}; - return bits; + return to_bid_d32(compliant_val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid_d32f(std::uint32_t bits) noexcept -> decimal32_fast +constexpr auto from_bid_d32f(std::uint32_t bits) noexcept -> decimal32_fast { - const auto compliant_val {detail::bit_cast(bits)}; + const auto compliant_val {from_bid_d32(bits)}; const decimal32_fast val {compliant_val}; return val; } From 917c21a154e7d7d36d1ef8a8eb71051f7d44b4a4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 10:05:12 -0400 Subject: [PATCH 39/77] Simplify and document d64 bid conversions --- doc/decimal/conversions.adoc | 4 +++- include/boost/decimal/bid_conversion.hpp | 10 ++++------ include/boost/decimal/decimal64.hpp | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 726d4e1af..531fc08f2 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -37,7 +37,9 @@ constexpr std::uint32_t to_bid_d32f(decimal32_fast val) noexcept; constexpr decimal32_fast from_bid_d32f(std::uint32_t bits) noexcept; -BOOST_DECIMAL_CXX20_CONSTEXPR std::uint64_t to_bid_d64(decimal64 val) noexcept; +constexpr std::uint64_t to_bid_d64(decimal64 val) noexcept; + +constexpr decimal64 from_bid_d64(std::uint64_t bits) noexcept; BOOST_DECIMAL_CXX20_CONSTEXPR std::uint64_t to_bid_d64f(decimal64_fast val) noexcept; diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index 0123d69f8..0fbbd7ceb 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -43,16 +43,14 @@ constexpr auto from_bid_d32f(std::uint32_t bits) noexcept -> decimal32_fast return val; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d64(decimal64 val) noexcept -> std::uint64_t +constexpr auto to_bid_d64(decimal64 val) noexcept -> std::uint64_t { - const auto bits {detail::bit_cast(val)}; - return bits; + return val.bits_; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64 +constexpr auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64 { - const auto val {detail::bit_cast(bits)}; - return val; + return from_bits(bits); } BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d64f(decimal64_fast val) noexcept -> std::uint64_t diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index b693ac1dd..14cc489b9 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -225,6 +225,10 @@ BOOST_DECIMAL_EXPORT class decimal64 final template friend constexpr auto sequential_less_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + friend constexpr auto to_bid_d64(decimal64 val) noexcept -> std::uint64_t; + + friend constexpr auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64; + public: // 3.2.3.1 construct/copy/destroy constexpr decimal64() noexcept = default; From e14ca7c38a17fcc22b542bfc698e1b965c82beec Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 10:11:00 -0400 Subject: [PATCH 40/77] Simplify and document d64_fast bid conversions --- doc/decimal/conversions.adoc | 4 +++- include/boost/decimal/bid_conversion.hpp | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 531fc08f2..5d386dce6 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -41,7 +41,9 @@ constexpr std::uint64_t to_bid_d64(decimal64 val) noexcept; constexpr decimal64 from_bid_d64(std::uint64_t bits) noexcept; -BOOST_DECIMAL_CXX20_CONSTEXPR std::uint64_t to_bid_d64f(decimal64_fast val) noexcept; +constexpr std::uint64_t to_bid_d64f(decimal64_fast val) noexcept; + +constexpr decimal64_fast from_bid_d64f(std::uint64_t bits) noexcept; BOOST_DECIMAL_CXX20_CONSTEXPR detail::uint128 to_bid_d128(decimal128 val) noexcept; diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index 0fbbd7ceb..372dd7bf8 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -53,16 +53,15 @@ constexpr auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64 return from_bits(bits); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d64f(decimal64_fast val) noexcept -> std::uint64_t +constexpr auto to_bid_d64f(decimal64_fast val) noexcept -> std::uint64_t { const decimal64 compliant_val {val}; - const auto bits {detail::bit_cast(compliant_val)}; - return bits; + return to_bid_d64(compliant_val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid_d64f(std::uint64_t bits) noexcept -> decimal64_fast +constexpr auto from_bid_d64f(std::uint64_t bits) noexcept -> decimal64_fast { - const auto compliant_val {detail::bit_cast(bits)}; + const auto compliant_val {from_bid_d64(bits)}; const decimal64_fast val {compliant_val}; return val; } From ec1059a46e6ecc92494bdeb1ae367182723eeeba Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 10:20:26 -0400 Subject: [PATCH 41/77] Simplify and document d128 bid conversions --- doc/decimal/conversions.adoc | 17 +++++++++++++---- include/boost/decimal/bid_conversion.hpp | 17 +++++++++++------ include/boost/decimal/decimal128.hpp | 8 ++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 5d386dce6..7efdf32c5 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -45,19 +45,28 @@ constexpr std::uint64_t to_bid_d64f(decimal64_fast val) noexcept; constexpr decimal64_fast from_bid_d64f(std::uint64_t bits) noexcept; -BOOST_DECIMAL_CXX20_CONSTEXPR detail::uint128 to_bid_d128(decimal128 val) noexcept; +constexpr detail::uint128 to_bid_d128(decimal128 val) noexcept; + +constexpr decimal128 from_bid_d128(detail::uint128 bits) noexcept; + +// Automatic detection if your platform has built-in unsigned __int128 or not to enable/disable the overload +#ifdef BOOST_DECIMAL_HAS_INT128 + +constexpr decimal128 from_bid_d128(unsigned __int128 bits) noexcept; + +#endif // BOOST_DECIMAL_HAS_INT128 template -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(T val) noexcept; +constexpr auto to_bid(T val) noexcept; template constexpr T from_bid(std::uint32_t bits) noexcept; template -BOOST_DECIMAL_CXX20_CONSTEXPR T from_bid(std::uint64_t bits) noexcept; +constexpr T from_bid(std::uint64_t bits) noexcept; template -BOOST_DECIMAL_CXX20_CONSTEXPR T from_bid(detail::uint128 bits) noexcept; +constexpr T from_bid(detail::uint128 bits) noexcept; // ----- DPD Conversions ----- diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index 372dd7bf8..02f9229f3 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -66,18 +66,23 @@ constexpr auto from_bid_d64f(std::uint64_t bits) noexcept -> decimal64_fast return val; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d128(decimal128 val) noexcept -> detail::uint128 +constexpr auto to_bid_d128(decimal128 val) noexcept -> detail::uint128 { - const auto bits {detail::bit_cast(val)}; - return bits; + return val.bits_; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid_d128(detail::uint128 bits) noexcept -> decimal128 +constexpr auto from_bid_d128(detail::uint128 bits) noexcept -> decimal128 { - const auto val {detail::bit_cast(bits)}; - return val; + return from_bits(bits); } +#ifdef BOOST_DECIMAL_HAS_INT128 +constexpr auto from_bits_d128(detail::uint128_t bits) noexcept -> decimal128 +{ + return from_bits(bits); +} +#endif + BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d128f(decimal128_fast val) noexcept -> detail::uint128 { const decimal128 compliant_val {val}; diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index 290ae153b..36bbf324b 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -228,6 +228,14 @@ BOOST_DECIMAL_EXPORT class decimal128 final friend constexpr auto not_finite(decimal128 rhs) noexcept -> bool; + friend constexpr auto to_bid_d128(decimal128 val) noexcept -> detail::uint128; + + friend constexpr auto from_bid_d128(detail::uint128 bits) noexcept -> decimal128; + + #ifdef BOOST_DECIMAL_HAS_INT128 + friend constexpr auto from_bid_d128(detail::uint128_t bits) noexcept -> decimal128; + #endif + public: // 3.2.4.1 construct/copy/destroy constexpr decimal128() noexcept = default; From 63c121f22df3a82bd7cc78d05928e1b7e2284071 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 10:28:07 -0400 Subject: [PATCH 42/77] Simplify and document d128f bid conversions --- doc/decimal/conversions.adoc | 10 ++++++ include/boost/decimal/bid_conversion.hpp | 42 ++++++++++++++---------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 7efdf32c5..4a97f4156 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -56,6 +56,16 @@ constexpr decimal128 from_bid_d128(unsigned __int128 bits) noexcept; #endif // BOOST_DECIMAL_HAS_INT128 +constexpr detail::uint128 to_bid_d128f(decimal128_fast val) noexcept; + +constexpr decimal128 from_bid_d128f(detail::uint128 bits) noexcept; + +#ifdef BOOST_DECIMAL_HAS_INT128 + +constexpr decimal128 from_bid_d128f(unsigned __int128 bits) noexcept; + +#endif // BOOST_DECIMAL_HAS_INT128 + template constexpr auto to_bid(T val) noexcept; diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index 02f9229f3..7659f2fc5 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -83,85 +83,93 @@ constexpr auto from_bits_d128(detail::uint128_t bits) noexcept -> decimal128 } #endif -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid_d128f(decimal128_fast val) noexcept -> detail::uint128 +constexpr auto to_bid_d128f(decimal128_fast val) noexcept -> detail::uint128 { const decimal128 compliant_val {val}; - const auto bits {detail::bit_cast(compliant_val)}; - return bits; + return to_bid_d128(compliant_val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid_d128f(detail::uint128 bits) noexcept -> decimal128_fast +constexpr auto from_bid_d128f(detail::uint128 bits) noexcept -> decimal128_fast { - const auto compliant_val {detail::bit_cast(bits)}; + const auto compliant_val {from_bid_d128(bits)}; const decimal128_fast val {compliant_val}; return val; } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(decimal32 val) noexcept -> std::uint32_t +#ifdef BOOST_DECIMAL_HAS_INT128 +constexpr auto from_bid_d128f(detail::uint128_t bits) noexcept -> decimal128_fast +{ + const auto compliant_val {from_bid_d128(bits)}; + const decimal128_fast val {compliant_val}; + return val; +} +#endif + +constexpr auto to_bid(decimal32 val) noexcept -> std::uint32_t { return to_bid_d32(val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(decimal32_fast val) noexcept -> std::uint32_t +constexpr auto to_bid(decimal32_fast val) noexcept -> std::uint32_t { return to_bid_d32f(val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(decimal64 val) noexcept -> std::uint64_t +constexpr auto to_bid(decimal64 val) noexcept -> std::uint64_t { return to_bid_d64(val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(decimal64_fast val) noexcept -> std::uint64_t +constexpr auto to_bid(decimal64_fast val) noexcept -> std::uint64_t { return to_bid_d64f(val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(decimal128 val) noexcept -> detail::uint128 +constexpr auto to_bid(decimal128 val) noexcept -> detail::uint128 { return to_bid_d128(val); } -BOOST_DECIMAL_CXX20_CONSTEXPR auto to_bid(decimal128_fast val) noexcept -> detail::uint128 +constexpr auto to_bid(decimal128_fast val) noexcept -> detail::uint128 { return to_bid_d128f(val); } template -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid(std::uint32_t bits) noexcept +constexpr auto from_bid(std::uint32_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { return from_bid_d32f(bits); } template <> -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid(std::uint32_t bits) noexcept -> decimal32 +constexpr auto from_bid(std::uint32_t bits) noexcept -> decimal32 { return from_bid_d32(bits); } template -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid(std::uint64_t bits) noexcept +constexpr auto from_bid(std::uint64_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { return from_bid_d64f(bits); } template <> -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid(std::uint64_t bits) noexcept -> decimal64 +constexpr auto from_bid(std::uint64_t bits) noexcept -> decimal64 { return from_bid_d64(bits); } template -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid(detail::uint128 bits) noexcept +constexpr auto from_bid(detail::uint128 bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { return from_bid_d128f(bits); } template <> -BOOST_DECIMAL_CXX20_CONSTEXPR auto from_bid(detail::uint128 bits) noexcept -> decimal128 +constexpr auto from_bid(detail::uint128 bits) noexcept -> decimal128 { return from_bid_d128(bits); } From 71fe57212fbb44fa48e344bda73ed51ca9bf93d3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 10:28:17 -0400 Subject: [PATCH 43/77] Add template overload to match from_bid --- include/boost/decimal/bid_conversion.hpp | 6 ++++++ test/test_bid_conversions.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index 7659f2fc5..cdb05cc4b 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -135,6 +135,12 @@ constexpr auto to_bid(decimal128_fast val) noexcept -> detail::uint128 return to_bid_d128f(val); } +template +constexpr auto to_bid(T val) noexcept +{ + return to_bid(val); +} + template constexpr auto from_bid(std::uint32_t bits) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) diff --git a/test/test_bid_conversions.cpp b/test/test_bid_conversions.cpp index 712366047..bf20e095b 100644 --- a/test/test_bid_conversions.cpp +++ b/test/test_bid_conversions.cpp @@ -18,7 +18,7 @@ void test() for (std::size_t i {}; i < 1024; ++i) { const T val {dist(rng)}; - const auto bits {to_bid(val)}; + const auto bits {to_bid(val)}; const T return_val {from_bid(bits)}; BOOST_TEST_EQ(val, return_val); } From c8113b31e346f3a3df6c7cbf9ab8a55751772fc7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 12:35:45 -0400 Subject: [PATCH 44/77] Add to dpd64 code --- include/boost/decimal/decimal64.hpp | 4 + include/boost/decimal/decimal64_fast.hpp | 4 + include/boost/decimal/dpd_conversion.hpp | 121 +++++++++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 14cc489b9..2341865a5 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -229,6 +229,10 @@ BOOST_DECIMAL_EXPORT class decimal64 final friend constexpr auto from_bid_d64(std::uint64_t bits) noexcept -> decimal64; + template + friend constexpr auto to_dpd_d64(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint64_t); + public: // 3.2.3.1 construct/copy/destroy constexpr decimal64() noexcept = default; diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 37e4712c8..09d862696 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -119,6 +119,10 @@ class decimal64_fast final friend constexpr auto not_finite(decimal64_fast 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); + public: constexpr decimal64_fast() noexcept = default; diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 75335a012..968125416 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -521,6 +521,127 @@ constexpr auto from_dpd(std::uint32_t bits) noexcept } +template +constexpr auto to_dpd_d64(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint64_t) +{ + static_assert(std::is_same::value || + std::is_same::value, "The input must be a 64-bit decimal type"); + + // In the non-finite cases the encodings are the same + // 3.5.2.a and 3.5.2.b + if (!isfinite(val)) + { + return to_bid(val); + } + + const auto sign {val.isneg()}; + const auto exp {val.unbiased_exponent()}; + const auto significand {val.full_significand()}; + + std::uint64_t dpd {}; + // Set the sign bit as applicable + if (sign) + { + dpd |= detail::d64_sign_mask; + } + + std::uint8_t d[std::numeric_limits::digits10] {}; + auto temp_sig {significand}; + for (int i = 15; i >= 0; --i) + { + d[i] = static_cast(temp_sig % 10U); + temp_sig /= 10U; + } + BOOST_DECIMAL_ASSERT(d[0] >= 0 && d[0] <= 9); + BOOST_DECIMAL_ASSERT(temp_sig == 0); + + constexpr std::uint64_t leading_two_exp_bits_mask {0b1100000000}; + const auto leading_two_bits {(exp & leading_two_exp_bits_mask) >> 8U}; + BOOST_DECIMAL_ASSERT(leading_two_bits >= 0 && leading_two_bits <= 2); + constexpr std::uint64_t trailing_exp_bits_mask {0b0011111111}; + const auto trailing_exp_bits {(exp & trailing_exp_bits_mask)}; + + std::uint64_t combination_field_bits {}; + + // Now based on what the value of d[0] and the leading bits of exp are we can set the value of the combination field + // See 3.5.2.c.1 + // If d0 is 8 or 9 then we follow section i + if (d[0] >= 8) + { + const auto d0_is_nine {d[0] == 9}; + switch (leading_two_bits) + { + case 0U: + combination_field_bits = d0_is_nine ? 0b11001 : 0b11000; + break; + case 1U: + combination_field_bits = d0_is_nine ? 0b11011 : 0b11010; + break; + case 2U: + combination_field_bits = d0_is_nine ? 0b11101 : 0b11100; + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + } + // If d0 is 0 to 7 then we follow section II + else + { + // In here the value of d[0] = 4*G2 + 2*G3 + G4 + const auto d0_mask {static_cast(d[0])}; + switch (leading_two_bits) + { + case 0U: + // 00XXX + combination_field_bits |= d0_mask; + break; + case 1U: + // 01XXX + combination_field_bits = 0b01000; + combination_field_bits |= d0_mask; + break; + case 2U: + // 10XXX + combination_field_bits = 0b10000; + combination_field_bits |= d0_mask; + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + } + + // Write the now known combination field and trailing exp bits to the result + dpd |= (combination_field_bits << 58U); + dpd |= (trailing_exp_bits << 50U); + + // Now we need to encode all the declets + // Once we have the declet right it into the result + int offset {4}; + for (std::size_t i {1}; i < 15; i += 3U) + { + const auto declet {static_cast(detail::encode_dpd(d[i], d[i + 1], d[i + 2]))}; + dpd |= (declet << (10 * offset)); + --offset; + } + + return dpd; +} + +constexpr auto to_dpd(decimal64 val) -> std::uint64_t +{ + return to_dpd_d64(val); +} + +constexpr auto to_dpd(decimal64_fast val) -> std::uint64_t +{ + return to_dpd_d64(val); +} + } // namespace decimal } // namespace boost From 428f2e664fd3e28de61eeb55276b2b53ebf49fe1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 13:39:53 -0400 Subject: [PATCH 45/77] Add from dpd64 --- include/boost/decimal/dpd_conversion.hpp | 92 ++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 968125416..73cfc25ed 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -632,6 +632,98 @@ constexpr auto to_dpd_d64(DecimalType val) noexcept return dpd; } +template +constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + // First we check for non-finite values + // Since they are in the same initial format as BID it's easy to check with our existing masks + if ((dpd & detail::d64_inf_mask) == detail::d64_inf_mask) + { + if ((dpd & detail::d64_snan_mask) == detail::d64_snan_mask) + { + return std::numeric_limits::signaling_NaN(); + } + else if ((dpd & detail::d64_nan_mask) == detail::d64_nan_mask) + { + return std::numeric_limits::quiet_NaN(); + } + else + { + return std::numeric_limits::infinity(); + } + } + + // The bit lengths are the same as used in the standard bid format + const auto sign {(dpd & detail::d32_sign_mask) != 0}; + const auto combination_field_bits {(dpd & detail::d64_combination_field_mask) >> 58U}; + const auto exponent_field_bits {(dpd & detail::d64_exponent_mask) >> 50U}; + auto significand_bits {(dpd & detail::d64_significand_mask)}; + + // Case 1: 3.5.2.c.1.i + // Combination field bits are 110XX or 11110X + std::uint64_t d0 {}; + std::uint64_t leading_biased_exp_bits {}; + if (combination_field_bits >= 0b11000) + { + // d0 = 8 + G4 + // Must be equal to 8 or 9 + d0 = 8U + (combination_field_bits & 0b00001); + BOOST_DECIMAL_ASSERT(d0 == 8 || d0 == 9); + + // leading exp bits are 2*G2 + G3 + // Must be equal to 0, 1 or 2 + leading_biased_exp_bits = 2U * ((combination_field_bits & 0b00100) >> 2U) + ((combination_field_bits & 0b00010) >> 1U); + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U); + } + // Case 2: 3.5.2.c.1.ii + // Combination field bits are 0XXXX or 10XXX + else + { + // d0 = 4 * G2 + 2 * G3 + G4 + // Must be in the range 0-7 + d0 = combination_field_bits & 0b00111; + BOOST_DECIMAL_ASSERT(d0 <= 7); + + // Leading exp bits are 2 * G0 + G1 + // Must be equal to 0, 1 or 2 + leading_biased_exp_bits = (combination_field_bits & 0b11000) >> 3U; + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U); + } + + // Now that we have the bits we can calculate the exponents value + const auto complete_exp {(leading_biased_exp_bits << 8U) + exponent_field_bits}; + const auto exp {static_cast(complete_exp) - detail::bias_v}; + + // We can now decode the remainder of the significand to recover the value + std::uint8_t digits[16] {}; + digits[0] = static_cast(d0); + for (int i = 15; i > 0; i -= 3) + { + const auto declet_bits {static_cast(significand_bits & 0b1111111111)}; + significand_bits >>= 10U; + detail::decode_dpd(declet_bits, digits[i], digits[i - 1], digits[i - 2]); + } + + std::uint64_t significand {}; + for (std::uint64_t i {}; i < 16U; ++i) + { + significand += digits[i] * detail::pow10(15 - i); + } + + return DecimalType{significand, exp, sign}; +} + +constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t +{ + return to_dpd_d32(val); +} + +constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t +{ + return to_dpd_d32(val); +} + constexpr auto to_dpd(decimal64 val) -> std::uint64_t { return to_dpd_d64(val); From 918938a74a037672791db81aa10dbfc985931afe Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 13:40:08 -0400 Subject: [PATCH 46/77] Refactor calling functions --- include/boost/decimal/dpd_conversion.hpp | 39 +++++++++++++----------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 73cfc25ed..9be92df8f 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -421,16 +421,6 @@ constexpr auto to_dpd_d32(DecimalType val) noexcept return dpd; } -constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t -{ - return to_dpd_d32(val); -} - -constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t -{ - return to_dpd_d32(val); -} - template constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) @@ -513,14 +503,6 @@ constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept return DecimalType{significand, exp, sign}; } -template -constexpr auto from_dpd(std::uint32_t bits) noexcept - BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) -{ - return from_dpd_d32(bits); -} - - template constexpr auto to_dpd_d64(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::uint64_t) @@ -734,6 +716,27 @@ constexpr auto to_dpd(decimal64_fast val) -> std::uint64_t return to_dpd_d64(val); } +template +constexpr auto to_dpd(DecimalType val) noexcept +{ + static_assert(detail::is_decimal_floating_point_v, "Must be a decimal floating point type."); + return to_dpd(val); +} + +template +constexpr auto from_dpd(std::uint32_t bits) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + return from_dpd_d32(bits); +} + +template +constexpr auto from_dpd(std::uint64_t bits) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + return from_dpd_d64(bits); +} + } // namespace decimal } // namespace boost From 39af8f95180bf3c6ae00f031e03f9167c99576e4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 13:42:53 -0400 Subject: [PATCH 47/77] Fix wrong mask usage --- include/boost/decimal/dpd_conversion.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 9be92df8f..81a267ba2 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -637,7 +637,7 @@ constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept } // The bit lengths are the same as used in the standard bid format - const auto sign {(dpd & detail::d32_sign_mask) != 0}; + const auto sign {(dpd & detail::d64_sign_mask) != 0}; const auto combination_field_bits {(dpd & detail::d64_combination_field_mask) >> 58U}; const auto exponent_field_bits {(dpd & detail::d64_exponent_mask) >> 50U}; auto significand_bits {(dpd & detail::d64_significand_mask)}; From 339a887bf4066da5da82aedfc8d194fe287d6e75 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 13:58:04 -0400 Subject: [PATCH 48/77] Add 64-bit decimal type testing --- test/test_dpd_conversions.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp index b0d64520d..f51789f43 100644 --- a/test/test_dpd_conversions.cpp +++ b/test/test_dpd_conversions.cpp @@ -11,7 +11,7 @@ using namespace boost::decimal; template T roundtrip(T val) { - const auto bits {to_dpd(val)}; + const auto bits {to_dpd(val)}; return from_dpd(bits); } @@ -41,9 +41,12 @@ void test() template void test_float_range() { + using float_type = std::conditional_t::value || + std::is_same::value, float, double>; + std::mt19937_64 rng(42); - std::uniform_real_distribution dist(std::numeric_limits::min(), - std::numeric_limits::max()); + std::uniform_real_distribution dist(std::numeric_limits::min(), + std::numeric_limits::max()); for (std::size_t i {}; i < 1024; ++i) { @@ -61,5 +64,11 @@ int main() test_float_range(); test_float_range(); + test(); + test(); + + test_float_range(); + test_float_range(); + return boost::report_errors(); } From 00959cd6cdeb5d0db4c895cfa4a48e825a36c136 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 14:41:09 -0400 Subject: [PATCH 49/77] Fix bid typo --- include/boost/decimal/bid_conversion.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/bid_conversion.hpp b/include/boost/decimal/bid_conversion.hpp index cdb05cc4b..683c87682 100644 --- a/include/boost/decimal/bid_conversion.hpp +++ b/include/boost/decimal/bid_conversion.hpp @@ -77,7 +77,7 @@ constexpr auto from_bid_d128(detail::uint128 bits) noexcept -> decimal128 } #ifdef BOOST_DECIMAL_HAS_INT128 -constexpr auto from_bits_d128(detail::uint128_t bits) noexcept -> decimal128 +constexpr auto from_bid_d128(detail::uint128_t bits) noexcept -> decimal128 { return from_bits(bits); } From 12c13a312634e73ce289ccb21c61b7d7ba5956a0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 14:44:24 -0400 Subject: [PATCH 50/77] Add conversions to the docs --- doc/decimal/conversions.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 4a97f4156..82ee90ae3 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -84,12 +84,31 @@ constexpr std::uint32_t to_dpd_d32(decimal32 val) noexcept; constexpr std::uint32_t to_dpd_d32f(decimal32_fast val) noexcept; +constexpr std::uint64_t to_dpd_d64(decimal64 val) noexcept; + +constexpr std::uint64_t to_dpd_d64f(decimal64_fast val) noexcept; + +constexpr detail::uint128 to_dpd_d128(decimal128 val) noexcept; + +constexpr detail::uint128 to_dpd_d128f(decimal128_fast val) noexcept; + template constexpr auto to_dpd(T val) noexcept; template constexpr T from_dpd(std::uint32_t bits) noexcept; +template +constexpr T from_dpd(std::uint64_t bits) noexcept; + +template +constexpr T from_dpd(detail::uint128 bits) noexcept; + +#ifdef BOOST_DECIMAL_HAS_INT128 +template +constexpr T from_dpd(unsigned __int128 bits) noexcept; +#endif + } // namespace decimal } // namespace boost ---- From fbfe630bf5ff1fac9bd98991bee248b9e7fe3c0e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 15:29:13 -0400 Subject: [PATCH 51/77] Add to_dpd_128 --- include/boost/decimal/decimal128.hpp | 4 + include/boost/decimal/dpd_conversion.hpp | 112 +++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index 36bbf324b..e3143e06d 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -236,6 +236,10 @@ BOOST_DECIMAL_EXPORT class decimal128 final friend constexpr auto from_bid_d128(detail::uint128_t bits) noexcept -> decimal128; #endif + template + friend constexpr auto to_dpd_d128(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, detail::uint128); + public: // 3.2.4.1 construct/copy/destroy constexpr decimal128() noexcept = default; diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 81a267ba2..400d68be9 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include @@ -696,6 +697,117 @@ constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept return DecimalType{significand, exp, sign}; } +template +constexpr auto to_dpd_d128(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, detail::uint128) +{ + static_assert(std::is_same::value || + std::is_same::value, "The input must be a 128-bit decimal type"); + + // In the non-finite cases the encodings are the same + // 3.5.2.a and 3.5.2.b + if (!isfinite(val)) + { + return to_bid(val); + } + + const auto sign {val.isneg()}; + const auto exp {val.unbiased_exponent()}; + const auto significand {val.full_significand()}; + + detail::uint128 dpd {}; + + // Set the sign bit as applicable + if (sign) + { + dpd.high |= detail::d128_sign_mask.high; + } + + constexpr int num_digits {std::numeric_limits::digits10}; + std::uint8_t d[num_digits] {}; + auto temp_sig {significand}; + for (int i = num_digits - 1; i >= 0; --i) + { + d[i] = static_cast(temp_sig % 10U); + temp_sig /= 10U; + } + BOOST_DECIMAL_ASSERT(d[0] >= 0 && d[0] <= 9); + BOOST_DECIMAL_ASSERT(temp_sig == 0); + + constexpr std::uint64_t leading_two_exp_bits_mask {0b11000000000000}; + const auto leading_two_bits {(exp & leading_two_exp_bits_mask) >> 12U}; + constexpr std::uint64_t trailing_exp_bits_mask {0b00111111111111}; + const auto trailing_exp_bits {(exp & trailing_exp_bits_mask)}; + + std::uint64_t combination_field_bits {}; + + // Now based on what the value of d[0] and the leading bits of exp are we can set the value of the combination field + // See 3.5.2.c.1 + // If d0 is 8 or 9 then we follow section i + if (d[0] >= 8) + { + const auto d0_is_nine {d[0] == 9}; + switch (leading_two_bits) + { + case 0U: + combination_field_bits = d0_is_nine ? 0b11001 : 0b11000; + break; + case 1U: + combination_field_bits = d0_is_nine ? 0b11011 : 0b11010; + break; + case 2U: + combination_field_bits = d0_is_nine ? 0b11101 : 0b11100; + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + } + // If d0 is 0 to 7 then we follow section II + else + { + // In here the value of d[0] = 4*G2 + 2*G3 + G4 + const auto d0_mask {static_cast(d[0])}; + switch (leading_two_bits) + { + case 0U: + // 00XXX + combination_field_bits |= d0_mask; + break; + case 1U: + // 01XXX + combination_field_bits = 0b01000; + combination_field_bits |= d0_mask; + break; + case 2U: + // 10XXX + combination_field_bits = 0b10000; + combination_field_bits |= d0_mask; + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + } + + // Write the now know combination field and trailing exp bits to the result + dpd.high |= (combination_field_bits << 58U); + dpd.high |= (trailing_exp_bits << 46U); + + // Now we have to encode all 10 of the declets + int offset {9}; + for (std::size_t i {1}; i < num_digits - 1; i += 3U) + { + const auto declet {static_cast(detail::encode_dpd(d[i], d[i + 1], d[i + 2]))}; + dpd |= (declet << (10 * offset)); + --offset; + } + + return dpd; +} + constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t { return to_dpd_d32(val); From 112051b5f768e13c53a1a48de2fad6cc4068e6aa Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 15:30:06 -0400 Subject: [PATCH 52/77] Add friend to d128_fast --- include/boost/decimal/decimal128_fast.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 0f79cf925..4d1de7f27 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -123,6 +123,10 @@ class decimal128_fast final friend constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool; + template + friend constexpr auto to_dpd_d128(DecimalType val) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, detail::uint128); + public: constexpr decimal128_fast() noexcept = default; From bcecb9ff95708a450a47f489da8363390da43c1f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 15:37:53 -0400 Subject: [PATCH 53/77] Add static assertion for target decimal type --- include/boost/decimal/dpd_conversion.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 400d68be9..76cbe97d9 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -426,6 +426,9 @@ template constexpr auto from_dpd_d32(std::uint32_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { + static_assert(std::is_same::value || std::is_same::value, + "Target decimal type must be 32-bits"); + // First we check for non-finite values // Since they are in the same initial format as BID it's easy to check with our existing masks if ((dpd & detail::d32_inf_mask) == detail::d32_inf_mask) @@ -619,6 +622,9 @@ template constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) { + static_assert(std::is_same::value || std::is_same::value, + "Target decimal type must be 64-bits"); + // First we check for non-finite values // Since they are in the same initial format as BID it's easy to check with our existing masks if ((dpd & detail::d64_inf_mask) == detail::d64_inf_mask) From 347a3aa06e15824ec5ed1dfdc7200458171422df Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 16:10:28 -0400 Subject: [PATCH 54/77] Add 128-bit from_dpd conversion overload --- include/boost/decimal/dpd_conversion.hpp | 117 ++++++++++++++++++++++- 1 file changed, 115 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index 76cbe97d9..e63f55888 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -814,6 +814,90 @@ constexpr auto to_dpd_d128(DecimalType val) noexcept return dpd; } +template +constexpr auto from_dpd_d128(detail::uint128 dpd) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + static_assert(std::is_same::value || std::is_same::value, + "Target decimal type must be 128-bits"); + + if ((dpd & detail::d128_inf_mask) == detail::d128_inf_mask) + { + if ((dpd & detail::d128_snan_mask) == detail::d128_snan_mask) + { + return std::numeric_limits::signaling_NaN(); + } + else if ((dpd & detail::d128_nan_mask) == detail::d128_nan_mask) + { + return std::numeric_limits::quiet_NaN(); + } + else + { + return std::numeric_limits::infinity(); + } + } + + // The bit lengths are the same as used in the standard bid format + const auto sign {(dpd.high & detail::d128_sign_mask.high) != 0}; + const auto combination_field_bits {(dpd.high & detail::d128_combination_field_mask.high) >> 58U}; + const auto exponent_field_bits {(dpd.high & detail::d128_exponent_mask.high) >> 46U}; + auto significand_bits {(dpd & detail::d128_significand_mask)}; + + // Case 1: 3.5.2.c.1.i + // Combination field bits are 110XX or 11110X + std::uint64_t d0 {}; + std::uint64_t leading_biased_exp_bits {}; + if (combination_field_bits >= 0b11000) + { + // d0 = 8 + G4 + // Must be equal to 8 or 9 + d0 = 8U + (combination_field_bits & 0b00001); + BOOST_DECIMAL_ASSERT(d0 == 8 || d0 == 9); + + // leading exp bits are 2*G2 + G3 + // Must be equal to 0, 1 or 2 + leading_biased_exp_bits = 2U * ((combination_field_bits & 0b00100) >> 2U) + ((combination_field_bits & 0b00010) >> 1U); + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U); + } + // Case 2: 3.5.2.c.1.ii + // Combination field bits are 0XXXX or 10XXX + else + { + // d0 = 4 * G2 + 2 * G3 + G4 + // Must be in the range 0-7 + d0 = combination_field_bits & 0b00111; + BOOST_DECIMAL_ASSERT(d0 <= 7); + + // Leading exp bits are 2 * G0 + G1 + // Must be equal to 0, 1 or 2 + leading_biased_exp_bits = (combination_field_bits & 0b11000) >> 3U; + BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U); + } + + // Now that we have the bits we can calculate the exponents value + const auto complete_exp {(leading_biased_exp_bits << 12U) + exponent_field_bits}; + const auto exp {static_cast(complete_exp) - detail::bias_v}; + + // We can now decode the remainder of the significand to recover the value + constexpr auto num_digits {std::numeric_limits::digits10}; + std::uint8_t digits[num_digits] {}; + digits[0] = static_cast(d0); + for (int i = num_digits - 1; i > 0; i -= 3) + { + const auto declet_bits {static_cast(significand_bits & 0b1111111111)}; + significand_bits >>= 10U; + detail::decode_dpd(declet_bits, digits[i], digits[i - 1], digits[i - 2]); + } + + detail::uint128 significand {}; + for (int i {}; i < num_digits; ++i) + { + significand += static_cast(digits[i]) * detail::pow10(static_cast(num_digits - i)); + } + + return DecimalType{significand, exp, sign}; +} + constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t { return to_dpd_d32(val); @@ -824,16 +908,26 @@ constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t return to_dpd_d32(val); } -constexpr auto to_dpd(decimal64 val) -> std::uint64_t +constexpr auto to_dpd(decimal64 val) noexcept -> std::uint64_t { return to_dpd_d64(val); } -constexpr auto to_dpd(decimal64_fast val) -> std::uint64_t +constexpr auto to_dpd(decimal64_fast val) noexcept -> std::uint64_t { return to_dpd_d64(val); } +constexpr auto to_dpd(decimal128 val) noexcept -> detail::uint128 +{ + return to_dpd_d128(val); +} + +constexpr auto to_dpd(decimal128_fast val) noexcept -> detail::uint128 +{ + return to_dpd_d128(val); +} + template constexpr auto to_dpd(DecimalType val) noexcept { @@ -855,6 +949,25 @@ constexpr auto from_dpd(std::uint64_t bits) noexcept return from_dpd_d64(bits); } +template +constexpr auto from_dpd(detail::uint128 bits) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + return from_dpd_d128(bits); +} + +#ifdef BOOST_DECIMAL_HAS_INT128 + +template +constexpr auto from_dpd(detail::uint128_t bits) noexcept + BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType) +{ + const detail::uint128 converted_bits {bits}; + return from_dpd_d128(converted_bits); +} + +#endif // BOOST_DECIMAL_HAS_INT128 + } // namespace decimal } // namespace boost From 7250c7c09d25242605eb14b94adbfe6e3153d6e8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 16:41:58 -0400 Subject: [PATCH 55/77] Fix conversion of declets --- include/boost/decimal/dpd_conversion.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index e63f55888..d3ed13603 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -802,12 +802,12 @@ constexpr auto to_dpd_d128(DecimalType val) noexcept dpd.high |= (combination_field_bits << 58U); dpd.high |= (trailing_exp_bits << 46U); - // Now we have to encode all 10 of the declets - int offset {9}; + // Now we have to encode all 11 of the declets + int offset {10}; for (std::size_t i {1}; i < num_digits - 1; i += 3U) { const auto declet {static_cast(detail::encode_dpd(d[i], d[i + 1], d[i + 2]))}; - dpd |= (declet << (10 * offset)); + dpd |= detail::uint128(declet << (10 * offset)); --offset; } @@ -892,7 +892,7 @@ constexpr auto from_dpd_d128(detail::uint128 dpd) noexcept detail::uint128 significand {}; for (int i {}; i < num_digits; ++i) { - significand += static_cast(digits[i]) * detail::pow10(static_cast(num_digits - i)); + significand += static_cast(digits[i]) * detail::pow10(static_cast((num_digits - 1) - i)); } return DecimalType{significand, exp, sign}; From 2f3b45103572cddcb5490f31aa401737836ddf98 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 16:44:24 -0400 Subject: [PATCH 56/77] Add 128-bit dpd conversion testing --- test/test_dpd_conversions.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_dpd_conversions.cpp b/test/test_dpd_conversions.cpp index f51789f43..da927cca9 100644 --- a/test/test_dpd_conversions.cpp +++ b/test/test_dpd_conversions.cpp @@ -70,5 +70,11 @@ int main() test_float_range(); test_float_range(); + test(); + test(); + + test_float_range(); + test_float_range(); + return boost::report_errors(); } From d55f5992dcb4304dd351c5f2ea36bc8ba483a239 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 30 Sep 2024 17:13:53 -0400 Subject: [PATCH 57/77] Fix MS platform conversion error --- include/boost/decimal/dpd_conversion.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/dpd_conversion.hpp b/include/boost/decimal/dpd_conversion.hpp index d3ed13603..7ce886f0a 100644 --- a/include/boost/decimal/dpd_conversion.hpp +++ b/include/boost/decimal/dpd_conversion.hpp @@ -730,7 +730,7 @@ constexpr auto to_dpd_d128(DecimalType val) noexcept } constexpr int num_digits {std::numeric_limits::digits10}; - std::uint8_t d[num_digits] {}; + std::uint8_t d[static_cast(num_digits)] {}; auto temp_sig {significand}; for (int i = num_digits - 1; i >= 0; --i) { @@ -880,7 +880,7 @@ constexpr auto from_dpd_d128(detail::uint128 dpd) noexcept // We can now decode the remainder of the significand to recover the value constexpr auto num_digits {std::numeric_limits::digits10}; - std::uint8_t digits[num_digits] {}; + std::uint8_t digits[static_cast(num_digits)] {}; digits[0] = static_cast(d0); for (int i = num_digits - 1; i > 0; i -= 3) { From 0cc882857980e0cecece373a520479726e5a3a3e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 17:01:09 -0400 Subject: [PATCH 58/77] Update benchmarks to use rather than boost.charconv --- test/benchmarks.cpp | 58 +++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/test/benchmarks.cpp b/test/benchmarks.cpp index 4b47be4c9..c261fcdf0 100644 --- a/test/benchmarks.cpp +++ b/test/benchmarks.cpp @@ -3,8 +3,13 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt +#if defined(__GNUC__) && __GNUC__ > 5 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wclass-memaccess" +# pragma GCC diagnostic ignored "-Warray-bounds" +#endif + #include -#include #include #include #include @@ -17,6 +22,15 @@ #ifdef BOOST_DECIMAL_RUN_BENCHMARKS +#if __cplusplus >= 201703L +#if __has_include() +# include +# if defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L +# define BOOST_DECIMAL_BENCHMARK_CHARCONV +# endif +#endif +#endif + using namespace boost::decimal; using namespace std::chrono_literals; @@ -165,8 +179,10 @@ static BOOST_DECIMAL_NO_INLINE void init_input_data( std::vector& data ) } } +#ifdef BOOST_DECIMAL_BENCHMARK_CHARCONV + template ::value, bool> = true> -static BOOST_NOINLINE void test_boost_to_chars( std::vector const& data, bool general, char const* label, int precision, const char* type ) +static BOOST_DECIMAL_NO_INLINE void test_boost_to_chars( std::vector const& data, bool general, char const* label, int precision, const char* type ) { auto t1 = std::chrono::steady_clock::now(); @@ -191,11 +207,11 @@ static BOOST_NOINLINE void test_boost_to_chars( std::vector const& data, bool auto t2 = std::chrono::steady_clock::now(); - std::cout << "boost::decimal::to_chars<" << std::left << std::setw(11) << type << ">, " << label << ", " << precision << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; + std::cout << "boost::decimal::to_chars<" << std::left << std::setw(11) << type << ">, " << label << ", " << precision << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; } template ::value, bool> = true> -static BOOST_NOINLINE void test_boost_to_chars( std::vector const& data, bool general, char const* label, int precision, const char* type ) +static BOOST_DECIMAL_NO_INLINE void test_boost_to_chars( std::vector const& data, bool general, char const* label, int precision, const char* type ) { auto t1 = std::chrono::steady_clock::now(); @@ -207,11 +223,11 @@ static BOOST_NOINLINE void test_boost_to_chars( std::vector const& data, bool for( auto x: data ) { - boost::charconv::chars_format fmt = general? boost::charconv::chars_format::general: boost::charconv::chars_format::scientific; + std::chars_format fmt = general ? std::chars_format::general : std::chars_format::scientific; auto r = precision == 0? - boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), x, fmt ): - boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), x, fmt, precision ); + std::to_chars( buffer, buffer + sizeof( buffer ), x, fmt ): + std::to_chars( buffer, buffer + sizeof( buffer ), x, fmt, precision ); s += static_cast( r.ptr - buffer ); s += static_cast( buffer[0] ); @@ -220,7 +236,7 @@ static BOOST_NOINLINE void test_boost_to_chars( std::vector const& data, bool auto t2 = std::chrono::steady_clock::now(); - std::cout << "boost::charconv::to_chars<" << std::left << std::setw(11) << type << ">, " << label << ", " << precision << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; + std::cout << " std::to_chars<" << std::left << std::setw(10) << type << ">, " << label << ", " << precision << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; } @@ -254,7 +270,7 @@ BOOST_DECIMAL_NO_INLINE void init_from_chars_input_data( std::vector con for( auto const& x: data ) { T y; - auto r = boost::charconv::from_chars( x.data(), x.data() + x.size(), y, general? boost::charconv::chars_format::general: boost::charconv::chars_format::scientific ); + auto r = std::from_chars( x.data(), x.data() + x.size(), y, general ? std::chars_format::general : std::chars_format::scientific ); s = static_cast(r.ec); } @@ -307,7 +323,7 @@ BOOST_DECIMAL_NO_INLINE void test_boost_from_chars( std::vector con auto t2 = std::chrono::steady_clock::now(); - std::cout << "boost::charconv::from_chars<" << std::left << std::setw(11) << type << ">, " << label << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; + std::cout << " std::from_chars<" << std::left << std::setw(11) << type << ">, " << label << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; } template ::value, bool> = true> @@ -329,7 +345,7 @@ BOOST_DECIMAL_NO_INLINE void test_boost_from_chars( std::vector con auto t2 = std::chrono::steady_clock::now(); - std::cout << "boost::decimal::from_chars<" << std::left << std::setw(11) << type << ">, " << label << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; + std::cout << "boost::decimal::from_chars<" << std::left << std::setw(11) << type << ">, " << label << ": " << std::setw( 10 ) << ( t2 - t1 ) / 1us << " us (s=" << s << ")\n"; } template @@ -342,6 +358,8 @@ void test_from_chars(bool general, const char* type) test_boost_from_chars( data, general, label, type ); } +#endif + int main() { const auto float_vector = generate_random_vector(); @@ -409,7 +427,7 @@ int main() test_two_element_operation(dec64_fast_vector, std::divides<>(), "Division", "dec64_fast"); test_two_element_operation(dec64_fast_vector, std::divides<>(), "Division", "dec128_fast"); -/* +#if 0 std::cout << "\n===== sqrt =====\n"; test_one_element_operation(float_vector, (float(*)(float))std::sqrt, "sqrt", "float"); @@ -417,13 +435,15 @@ int main() test_one_element_operation(dec32_vector, (decimal32(*)(decimal32))sqrt, "sqrt", "decimal32"); test_one_element_operation(dec64_vector, (decimal64(*)(decimal64))sqrt, "sqrt", "decimal64"); test_one_element_operation(dec128_vector, (decimal128(*)(decimal128))sqrt, "sqrt", "decimal128"); - +#endif +#ifdef BOOST_DECIMAL_BENCHMARK_CHARCONV std::cout << "\n===== to_chars =====\n"; test_to_chars("float"); test_to_chars("double"); test_to_chars("decimal32"); test_to_chars("decimal64"); - test_to_chars("decimal128"); + test_to_chars("dec32_fast"); + test_to_chars("dec64_fast"); std::cout << "\n===== from_chars =====\n"; test_from_chars(false, "float"); @@ -434,9 +454,11 @@ int main() test_from_chars(true, "decimal32"); test_from_chars(false, "decimal64"); test_from_chars(true, "decimal64"); - test_from_chars(false, "decimal128"); - test_from_chars(true, "decimal128"); -*/ + test_from_chars(false, "dec32_fast"); + test_from_chars(true, "dec32_fast"); + test_from_chars(false, "dec64_fast"); + test_from_chars(true, "dec64_fast"); +#endif std::cout << std::endl; return 1; From 38b06dc4f35e4242dfeb9282837dca5bcfdb4230 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 11:41:52 -0400 Subject: [PATCH 59/77] Add in section for benchmarks --- doc/decimal/benchmarks.adoc | 222 +++++++++++++++++------------------- 1 file changed, 105 insertions(+), 117 deletions(-) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index b2ff69d33..e82b47c16 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -387,199 +387,187 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home | 103.280 |=== -//// -These are not available for the built-ins so not deleting but also not incorporating - -== Selected Special Functions - -The benchmark for these operations generates a random vector containing 2,000,000 elements and does operations `+`, `-`, `*`, `/` between `vec[i] and vec[i + 1]`. -This is repeated 5 times to generate stable results. - -=== M1 macOS Results +== `` -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Parsing and serializing number exactly is one of the key features of decimal floating point types, so we must compare the performance of ``. For all the following the results compare against STL provided `` for 20,000,000 conversions. +Since `` is fully implemented in software for each type the performance gap between built-in `float` and `double` vs `decimal32` and `decimal64` is significantly smaller (or the decimal performance is better) than the hardware vs software performance gap seen above for basic operations. -==== SQRT +To run these benchmarks yourself you will need a compiler with complete implementation of `` and to run the benchmarks under C++17 or higher. +At the time of writing this is limited to: -|=== -| Type | Runtime (us) | Ratio to `double` -| `float` -| 2021 -| 0.626 -| `double` -| 3229 -| 1.000 -| `decimal32` -| 4,826,066 -| 1494.601 -| `decimal64` -| 7,780,637 -| 2409.612 -| `decimal128` -| 100,269,145 -| 31052.693 -|=== +- GCC 11 or newer +- MSVC 19.24 or newer -== `` +These benchmarks are automatically disabled if your compiler does not provide feature complete `` or if the language standard is set to C++14. -For all the following the results compare against https://github.com/boostorg/charconv[boost.charconv] for 10'000'000 conversions. +=== `from_chars` -=== `from_chars` general +==== `from_chars` general -==== M1 macOS Results +===== M1 macOS Results -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 235,816 -| 0.953 +| 2,556,533 +| 0.965 | `double` -| 247,307 +| 2,648,485 | 1.000 | `decimal32` -| 366,682 -| 1.483 +| 3,201,545 +| 1.209 | `decimal64` -| 485,965 -| 1.965 -// Decimal128 was two orders of magnitude faster. I expect an issue -//| `decimal128` -//| 275,779,340 -//| 73267.60 +| 4,775,487 +| 1.803 +| `decimal32_fast` +| 3,196,724 +| 1.207 +| `decimal64_fast` +| 4,762,636 +| 1.798 |=== -NOTE: `decimal128` is currently absent due to results showing it is 2 orders of magnitude faster than the others. -This should not be the case so will be investigated. - -=== `from_chars` scientific +==== `from_chars` scientific -==== M1 macOS Results +===== M1 macOS Results -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 241,893 -| 0.975 +| 2,651,707 +| 0.986 | `double` -| 247,975 +| 2,690,166 | 1.000 | `decimal32` -| 358,189 -| 1.444 +| 3,153,821 +| 1.172 | `decimal64` -| 477,574 +| 4,726,009 | 1.926 -// Decimal128 was two orders of magnitude faster. I expect an issue -//| `decimal128` -//| 275,779,340 -//| 73267.60 +| `decimal32_fast` +| 4,726,009 +| 1.757 +| `decimal64_fast` +| 4,693,387 +| 1.747 |=== -NOTE: `decimal128` is currently absent due to results showing it is 2 orders of magnitude faster than the others. -This should not be the case so will be investigated. +=== `to_chars` -=== `to_chars` general shortest representation +==== `to_chars` general shortest representation -==== M1 macOS Results +===== M1 macOS Results -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 316,300 -| 1.040 +| 2,917,920 +| 0.849 | `double` -| 304,272 +| 3,435,671 | 1.000 | `decimal32` -| 406,053 -| 1.335 +| 4,636,747 +| 1.350 | `decimal64` -| 678,451 -| 2.230 -| `decimal128` -| 6,309,346 -| 20.736 +| 5,680,800 +| 1.653 +| `decimal32_fast` +| 4,675,951 +| 1.361 +| `decimal64_fast` +| 5,900,272 +| 1.717 |=== -=== `to_chars` general 6-digits of precision +==== `to_chars` general 6-digits of precision -==== M1 macOS Results +===== M1 macOS Results -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 323,867 -| 0.967 +| 6,320,719 +| 0.962 | `double` -| 334,989 +| 6,572,846 | 1.000 | `decimal32` -| 409,608 -| 1.223 +| 4,133,466 +| 0.629 | `decimal64` -| 702,339 -| 2.097 -| `decimal128` -| 6,305,521 -| 18.823 +| 6,106,989 +| 0.929 +| `decimal32_fast` +| 3,458,534 +| 0.526 +| `decimal64_fast` +| 5,997,442 +| 0.912 |=== -=== `to_chars` scientific shortest representation +==== `to_chars` scientific shortest representation -==== M1 macOS Results +===== M1 macOS Results -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 286,330 -| 1.011 +| 2,814,527 +| 0.817 | `double` -| 283,287 +| 3,442,930 | 1.000 | `decimal32` -| 290,117 -| 1.024 +| 3,048,663 +| 0.885 | `decimal64` -| 499,637 -| 1.764 -| `decimal128` -| 3,096,910 -| 10.932 +| 3,786,216 +| 1.010 +| `decimal32_fast` +| 2,813,360 +| 0.817 +| `decimal64_fast` +| 4,082,146 +| 1.186 |=== -=== `to_chars` scientific 6-digits of precision +==== `to_chars` scientific 6-digits of precision -==== M1 macOS Results +===== M1 macOS Results -Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 +Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 258,710 -| 0.809 +| 5,636,010 +| 0.952 | `double` -| 319,676 +| 5,922,301 | 1.000 | `decimal32` -| 292,250 -| 0.914 +| 3,048,058 +| 0.515 | `decimal64` -| 516,399 -| 1.615 -| `decimal128` -| 3,108,380 -| 9.724 +| 5,140,604 +| 0.868 +| `decimal32_fast` +| 2,821,707 +| 0.476 +| `decimal64_fast` +| 5,525,549 +| 0.933 |=== - -//// From d92e67747f92f10e4db0b0f0a9aae2ce23803aaa Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 13:00:16 -0400 Subject: [PATCH 60/77] Add explanation for dec128_fast mul being slower than dec128 --- doc/decimal/benchmarks.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index e82b47c16..d9c7c8347 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -356,6 +356,9 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home | 12,573,178 | 705.526 |=== +As discussed in the design of the fast types the significand is stored in normalized form so that we do not have to worry about the effects of cohorts. +Unfortunately this means that `decimal128_fast` multiplication is always carried out internally at 256-bit size whereas `decimal128` contains heuristics in `operator*` to avoid 256-bit multiplication when it is not needed (i.e. the resultant significand is less than or equal to 128-bits). +This causes multiplication of `decimal128_fast` to be ~1.72x slower than `decimal128`, but all other operators leave us with a geometric average runtime under 1.00 for `decimal128_fast` / `decimal128` so we accept this tradeoff. ==== Division From 15166070a4f96d547f5a64ff6039d65d97aee745 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 13:03:10 -0400 Subject: [PATCH 61/77] Re-run and update all macos benchmarks --- doc/decimal/benchmarks.adoc | 151 ++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 75 deletions(-) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index d9c7c8347..1c7d6ff00 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -73,29 +73,29 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 146,976 -| 2.319 +| 131,803 +| 2.060 | `double` -| 63,382 +| 63,981 | 1.000 | `decimal32` -| 1,797,597 -| 28.361 +| 2,052,770 +| 32.084 | `decimal64` -| 2,799,376 -| 44.167 +| 2,701,290 +| 42.220 | `decimal128` -| 6,478,939 -| 102.220 +| 5,545,490 +| 86.674 | `decimal32_fast` -| 1,070,232 -| 16.885 +| 728,146 +| 11.381 | `decimal64_fast` -| 1,111,273 -| 17.533 +| 611,866 +| 9.563 | `decimal128_fast` -| 1,118,976 -| 17.654 +| 714,586 +| 11.169 |=== == Basic Operations @@ -272,29 +272,29 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 16,685 -| 0.955 +| 43,056 +| 1.295 | `double` -| 17,476 +| 33,238 | 1.000 | `decimal32` -| 2,528,095 -| 144.661 +| 3,146,032 +| 94.652 | `decimal64` -| 2,713,507 -| 155.270 +| 2,963,788 +| 89.169 | `decimal128` -| 11,969,714 -| 684.923 +| 10,125,221 +| 304.628 | `decimal32_fast` -| 1,423,277 -| 81.442 +| 1,685,360 +| 50.706 | `decimal64_fast` -| 1,280,409 -| 73.267 +| 1,886,022 +| 56.743 | `decimal128_fast` -| 6,047,499 -| 346.046 +| 6,893,049 +| 207.385 |=== ==== Subtraction @@ -302,29 +302,29 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 16,302 -| 1.045 +| 43,013 +| 1.295 | `double` -| 17,033 +| 33,204 | 1.000 | `decimal32` -| 2,010,525 -| 118.037 +| 2,385,896 +| 71.586 | `decimal64` -| 2,237,729 -| 131.376 +| 2,759,536 +| 83.108 | `decimal128` -| 6,907,396 -| 405.530 +| 5,560,295 +| 167.459 | `decimal32_fast` -| 1,378,448 -| 80.928 +| 1,228,630 +| 37.002 | `decimal64_fast` -| 1,276,731 -| 74.956 +| 1,312,815 +| 39.538 | `decimal128_fast` -| 2,970,586 -| 174.401 +| 2,869,005 +| 86.405 |=== ==== Multiplication @@ -332,30 +332,31 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 16,499 -| 0.926 +| 42,634 +| 1.293 | `double` -| 17,821 +| 32,970 | 1.000 | `decimal32` -| 1,951,504 -| 109.506 +| 2,826,351 +| 85.725 | `decimal64` -| 2,480,528 -| 139.191 +| 3,268,243 +| 99.128 | `decimal128` -| 14,360,630 -| 805.826 +| 4,654,643 +| 141.178 | `decimal32_fast` -| 630,355 -| 35.371 +| 1,614,365 +| 48.965 | `decimal64_fast` -| 987,703 -| 55.424 +| 2,417,646 +| 73.329 | `decimal128_fast` -| 12,573,178 -| 705.526 +| 8,017,934 +| 243.189 |=== + As discussed in the design of the fast types the significand is stored in normalized form so that we do not have to worry about the effects of cohorts. Unfortunately this means that `decimal128_fast` multiplication is always carried out internally at 256-bit size whereas `decimal128` contains heuristics in `operator*` to avoid 256-bit multiplication when it is not needed (i.e. the resultant significand is less than or equal to 128-bits). This causes multiplication of `decimal128_fast` to be ~1.72x slower than `decimal128`, but all other operators leave us with a geometric average runtime under 1.00 for `decimal128_fast` / `decimal128` so we accept this tradeoff. @@ -365,29 +366,29 @@ This causes multiplication of `decimal128_fast` to be ~1.72x slower than `decima |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 20,267 -| 0.841 +| 46,030 +| 1.351 | `double` -| 24,111 +| 34,078 | 1.000 | `decimal32` -| 1,757,506 -| 72.892 +| 2,649,922 +| 77.760 | `decimal64` -| 3,496,913 -| 145.033 +| 3,721,028 +| 109.192 | `decimal128` -| 20,017,989 -| 830.243 +| 19,559,739 +| 573.970 | `decimal32_fast` -| 846,727 -| 35.118 +| 1,436,099 +| 42.142 | `decimal64_fast` -| 2,484,985 -| 103.064 +| 2,593,573 +| 76.107 | `decimal128_fast` -| 2,490,175 -| 103.280 +| 2,594,426 +| 76.132 |=== == `` From 8245e51a09c08818cde085825e444b79258c0e06 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 14:15:56 -0400 Subject: [PATCH 62/77] Move discussion of operator* --- doc/decimal/benchmarks.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index 1c7d6ff00..a647899c5 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -103,6 +103,10 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr The benchmark for these operations generates a random vector containing 20,000,000 elements and does operations `+`, `-`, `*`, `/` between `vec[i] and vec[i + 1]`. This is repeated 5 times to generate stable results. +As discussed in the design of the fast types the significand is stored in normalized form so that we do not have to worry about the effects of cohorts. +Unfortunately this means that `decimal128_fast` multiplication is always carried out internally at 256-bit size whereas `decimal128` contains heuristics in `operator*` to avoid 256-bit multiplication when it is not needed (i.e. the resultant significand is less than or equal to 128-bits). +This causes multiplication of `decimal128_fast` to be ~1.72x slower than `decimal128`, but all other operators leave us with a geometric average runtime under 1.00 for `decimal128_fast` / `decimal128` so we accept this tradeoff. + === x64 Linux Results Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 @@ -357,10 +361,6 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home | 243.189 |=== -As discussed in the design of the fast types the significand is stored in normalized form so that we do not have to worry about the effects of cohorts. -Unfortunately this means that `decimal128_fast` multiplication is always carried out internally at 256-bit size whereas `decimal128` contains heuristics in `operator*` to avoid 256-bit multiplication when it is not needed (i.e. the resultant significand is less than or equal to 128-bits). -This causes multiplication of `decimal128_fast` to be ~1.72x slower than `decimal128`, but all other operators leave us with a geometric average runtime under 1.00 for `decimal128_fast` / `decimal128` so we accept this tradeoff. - ==== Division |=== From c3c98b4a3ff7f9e85e9017393ed9b36001b55607 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 14:23:45 -0400 Subject: [PATCH 63/77] Update x64 linux basic timing benchmarks --- doc/decimal/benchmarks.adoc | 178 ++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index a647899c5..62ef4b125 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -32,38 +32,38 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 35,581 +| 34,814 | 0.604 | `double` -| 58,848 +| 57,644 | 1.000 | `decimal32` -| 2,410,084 -| 40.954 +| 2,163,595 +| 37.534 | `decimal64` -| 4,233,175 -| 71.934 +| 2,633,923 +| 45.693 | `decimal128` -| 6,337,447 -| 107.692 +| 6,064,630 +| 105.208 | `decimal32_fast` -| 628,241 -| 10.676 +| 613,626 +| 10.645 | `decimal64_fast` -| 724,474 -| 12.311 +| 693,390 +| 12.029 | `decimal128_fast` -| 517,930 -| 8.801 +| 628,596 +| 10.905 | GCC `_Decimal32` | 893,375 -| 15.181 +| 15.498 | GCC `_Decimal64` | 496,127 -| 8.431 +| 8.607 | GCC `_Decimal128` | 1,143,636 -| 19.434 +| 19.840 |=== === M1 macOS Results @@ -116,38 +116,38 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 54,566 -| 1.077 +| 55,811 +| 1.062 | `double` -| 50,640 +| 52,531 | 1.000 | `decimal32` -| 3,639,957 -| 71.879 +| 2,653,456 +| 50.512 | `decimal64` -| 4,172,318 -| 82.392 +| 3,254,833 +| 61.960 | `decimal128` -| 10,936,595 -| 215.968 +| 10,479,050 +| 199.483 | `decimal32_fast` -| 1,148,249 -| 22.675 +| 1,371,022 +| 26.100 | `decimal64_fast` -| 1,149,203 -| 22.694 +| 1,370,192 +| 26.083 | `decimal128_fast` -| 7,424,598 -| 146.615 +| 7,197,718 +| 137.018 | GCC `_Decimal32` | 2,997,658 -| 50.939 +| 57.065 | GCC `_Decimal64` | 2,129,898 -| 36.193 +| 40.546 | GCC `_Decimal128` | 3,056,979 -| 51.947 +| 58.194 |=== ==== Subtraction @@ -155,38 +155,38 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 48,654 -| 0.912 +| 53,362 +| 1.083 | `double` -| 53,348 +| 49,242 | 1.000 | `decimal32` -| 2,850,709 -| 53.436 +| 2,054,535 +| 41.723 | `decimal64` -| 3,493,936 -| 65.493 +| 2,507,709 +| 50.926 | `decimal128` -| 10,492,728 -| 196.685 +| 5,554,139 +| 112.793 | `decimal32_fast` -| 1,012,199 -| 18.974 +| 1,050,225 +| 21.328 | `decimal64_fast` -| 1,055,476 -| 19.785 +| 1,048,560 +| 21.294 | `decimal128_fast` -| 2,114,185 -| 39.630 +| 2,073,580 +| 42.110 | GCC `_Decimal32` | 2,006,964 -| 37.620 +| 40.757 | GCC `_Decimal64` | 1,324,796 -| 24.833 +| 26.904 | GCC `_Decimal128` | 2,783,553 -| 52.177 +| 56.528 |=== ==== Multiplication @@ -194,38 +194,38 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 53,405 -| 1.101 +| 53,469 +| 1.093 | `double` -| 48,497 +| 48,903 | 1.000 | `decimal32` -| 2,708,779 -| 55.855 +| 1,993,989 +| 40.774 | `decimal64` -| 2,761,465 -| 56.941 +| 2,766,602 +| 56.573 | `decimal128` -| 8,509,678 -| 175.468 +| 4,796,346 +| 98.079 | `decimal32_fast` -| 451,679 -| 9.313 +| 1,117,727 +| 22.856 | `decimal64_fast` -| 777,927 -| 16.041 +| 1,369,834 +| 28.011 | `decimal128_fast` -| 13,970,509 -| 288.070 +| 8,139,518 +| 166.442 | GCC `_Decimal32` | 2,507,998 -| 51.714 +| 51.285 | GCC `_Decimal64` | 2,414,864 -| 49.794 +| 49.381 | GCC `_Decimal128` | 6,248,956 -| 128.852 +| 127.783 |=== ==== Division @@ -233,38 +233,38 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 |=== | Type | Runtime (us) | Ratio to `double` | `float` -| 58,955 -| 0.755 +| 59,003 +| 0.756 | `double` -| 78,046 +| 78,078 | 1.000 | `decimal32` -| 2,907,134 -| 37.249 +| 2,250,186 +| 28.820 | `decimal64` -| 3,464,841 -| 44.394 +| 2,816,014 +| 36.067 | `decimal128` -| 18,202,742 -| 233.231 +| 18,320,634 +| 234.645 | `decimal32_fast` -| 1,092,346 -| 13.996 +| 1,123,428 +| 14.389 | `decimal64_fast` -| 1,207,648 -| 15.474 +| 1,258,004 +| 16.112 | `decimal128_fast` -| 1,208,184 -| 15.480 +| 1,243,024 +| 15.920 | GCC `_Decimal32` | 5,002,197 -| 64.093 +| 64.067 | GCC `_Decimal64` | 2,961,731 -| 37.900 +| 37.933 | GCC `_Decimal128` | 10,095,995 -| 129.360 +| 129.307 |=== === M1 macOS Results From 38c7a4346054c4fbc05220f94d1809b7b91b0bd9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 14:40:42 -0400 Subject: [PATCH 64/77] Add x64 linux benchmarks --- doc/decimal/benchmarks.adoc | 156 ++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index 62ef4b125..76f7d98dc 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -408,6 +408,32 @@ These benchmarks are automatically disabled if your compiler does not provide fe ==== `from_chars` general +===== x64 Linux Results + +Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 10,308,818 +| 0.551 +| `double` +| 18,692,513 +| 1.000 +| `decimal32` +| 3,301,003 +| 0.177 +| `decimal64` +| 4,580,001 +| 0.245 +| `decimal32_fast` +| 3,321,788 +| 0.178 +| `decimal64_fast` +| 4,591,311 +| 0.246 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -436,6 +462,32 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr ==== `from_chars` scientific +===== x64 Linux Results + +Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 10,363,219 +| 0.554 +| `double` +| 18,677,179 +| 1.000 +| `decimal32` +| 3,296,877 +| 0.177 +| `decimal64` +| 4,500,127 +| 0.241 +| `decimal32_fast` +| 3,381,651 +| 0.181 +| `decimal64_fast` +| 4,496,194 +| 0.241 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -466,6 +518,32 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr ==== `to_chars` general shortest representation +===== x64 Linux Results + +Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 2,839,146 +| 0.841 +| `double` +| 3,374,946 +| 1.000 +| `decimal32` +| 4,253,304 +| 1.260 +| `decimal64` +| 6,885,679 +| 2.040 +| `decimal32_fast` +| 4,453,957 +| 1.320 +| `decimal64_fast` +| 7,827,910 +| 2.319 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -494,6 +572,32 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr ==== `to_chars` general 6-digits of precision +===== x64 Linux Results + +Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 5,226,353 +| 0.957 +| `double` +| 5,458,987 +| 1.000 +| `decimal32` +| 3,782,692 +| 0.693 +| `decimal64` +| 5,368,162 +| 0.983 +| `decimal32_fast` +| 3,611,498 +| 0.662 +| `decimal64_fast` +| 6,025,340 +| 1.104 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -522,6 +626,32 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr ==== `to_chars` scientific shortest representation +===== x64 Linux Results + +Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 2,835,528 +| 0.849 +| `double` +| 3,338,216 +| 1.000 +| `decimal32` +| 2,887,451 +| 0.865 +| `decimal64` +| 5,218,195 +| 1.563 +| `decimal32_fast` +| 3,033,115 +| 0.909 +| `decimal64_fast` +| 6,103,323 +| 1.828 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -550,6 +680,32 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebr ==== `to_chars` scientific 6-digits of precision +===== x64 Linux Results + +Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 4,686,460 +| 0.938 +| `double` +| 4,993,886 +| 1.000 +| `decimal32` +| 2,919,727 +| 0.585 +| `decimal64` +| 4,157,802 +| 0.833 +| `decimal32_fast` +| 3,052,228 +| 0.611 +| `decimal64_fast` +| 5,597,538 +| 1.121 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 From eedafdfcc914ab711489cbf6e0b6aa6690b2bc18 Mon Sep 17 00:00:00 2001 From: mborland Date: Wed, 2 Oct 2024 16:20:50 -0400 Subject: [PATCH 65/77] Add windows benchmarks of basic operations --- doc/decimal/benchmarks.adoc | 156 ++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index 76f7d98dc..2d6a05d3f 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -66,6 +66,38 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 19.840 |=== +=== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 182,707 +| 0.943 +| `double` +| 193,737 +| 1.000 +| `decimal32` +| 3,097,942 +| 15.990 +| `decimal64` +| 4,697,948 +| 24.249 +| `decimal128` +| 17,267,609 +| 89.129 +| `decimal32_fast` +| 809,847 +| 4.180 +| `decimal64_fast` +| 1,043,657 +| 5.387 +| `decimal128_fast` +| 888,053 +| 4.584 +|=== + === M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew Clang 18.1.8 @@ -267,6 +299,130 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 129.307 |=== +=== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +==== Addition + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 67,019 +| 0.974 +| `double` +| 68,820 +| 1.000 +| `decimal32` +| 2,994,405 +| 43.511 +| `decimal64` +| 4,531,755 +| 65.849 +| `decimal128` +| 25,209,554 +| 366.311 +| `decimal32_fast` +| 2,066,728 +| 30.031 +| `decimal64_fast` +| 3,667,169 +| 53.286 +| `decimal128_fast` +| 11,213,280 +| 162.936 +|=== + +==== Subtraction + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 60,912 +| 0.976 +| `double` +| 62,409 +| 1.000 +| `decimal32` +| 3,132,613 +| 50.194 +| `decimal64` +| 3,864,498 +| 61.992 +| `decimal128` +| 17,210,173 +| 275.764 +| `decimal32_fast` +| 2,028,429 +| 32.502 +| `decimal64_fast` +| 3,017,419 +| 48.349 +| `decimal128_fast` +| 5,557,846 +| 89.055 +|=== + +==== Multiplication + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 60,742 +| 0.969 +| `double` +| 62,658 +| 1.000 +| `decimal32` +| 2,029,689 +| 32.393 +| `decimal64` +| 8,805,524 +| 140.533 +| `decimal128` +| 15,519,053 +| 247.689 +| `decimal32_fast` +| 1,573,280 +| 25.109 +| `decimal64_fast` +| 7,650,156 +| 122.094 +| `decimal128_fast` +| 16,874,890 +| 269.317 +|=== + +==== Division + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 75,437 +| 0.936 +| `double` +| 80,559 +| 1.000 +| `decimal32` +| 2,832,016 +| 45.198 +| `decimal64` +| 11,640,789 +| 185.783 +| `decimal128` +| 32,470,044 +| 518.211 +| `decimal32_fast` +| 1,660,332 +| 26.498 +| `decimal64_fast` +| 11,266,972 +| 179.817 +| `decimal128_fast` +| 11,201,820 +| 178.777 +|=== + === M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and homebrew Clang 18.1.4 From bff6741e1a4b8b45e34532e07389e53210128c90 Mon Sep 17 00:00:00 2001 From: mborland Date: Wed, 2 Oct 2024 16:21:19 -0400 Subject: [PATCH 66/77] Add windows benchmarks of --- doc/decimal/benchmarks.adoc | 156 ++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/doc/decimal/benchmarks.adoc b/doc/decimal/benchmarks.adoc index 2d6a05d3f..26001aec6 100644 --- a/doc/decimal/benchmarks.adoc +++ b/doc/decimal/benchmarks.adoc @@ -590,6 +590,32 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 0.246 |=== +===== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 8,577,201 +| 0.410 +| `double` +| 20,903,459 +| 1.000 +| `decimal32` +| 4,602,771 +| 0.220 +| `decimal64` +| 5,332,730 +| 0.255 +| `decimal32_fast` +| 3,932,622 +| 0.188 +| `decimal64_fast` +| 5,614,476 +| 0.269 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -644,6 +670,32 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 0.241 |=== +===== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 8,170,079 +| 0.439 +| `double` +| 18,626,905 +| 1.000 +| `decimal32` +| 3,927,882 +| 0.211 +| `decimal64` +| 5,668,246 +| 0.304 +| `decimal32_fast` +| 3,904,457 +| 0.210 +| `decimal64_fast` +| 5,302,174 +| 0.285 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -700,6 +752,32 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 2.319 |=== +===== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 3,108,053 +| 0.823 +| `double` +| 3,774,811 +| 1.000 +| `decimal32` +| 6,127,529 +| 1.623 +| `decimal64` +| 8,582,256 +| 2.273 +| `decimal32_fast` +| 7,639,470 +| 2.024 +| `decimal64_fast` +| 11,564,222 +| 3.064 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -754,6 +832,32 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 1.104 |=== +===== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 5,873,775 +| 0.929 +| `double` +| 6,322,448 +| 1.000 +| `decimal32` +| 5,493,981 +| 0.869 +| `decimal64` +| 7,849,419 +| 1.215 +| `decimal32_fast` +| 6,516,633 +| 1.031 +| `decimal64_fast` +| 8,065,516 +| 1.276 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -808,6 +912,32 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 1.828 |=== +===== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 3,047,827 +| 0.814 +| `double` +| 3,742,344 +| 1.000 +| `decimal32` +| 4,103,661 +| 1.097 +| `decimal64` +| 6,721,570 +| 1.796 +| `decimal32_fast` +| 4,542,470 +| 1.214 +| `decimal64_fast` +| 8,694,813 +| 2.323 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 @@ -862,6 +992,32 @@ Run using an Intel i9-11900k chipset running RHEL 9.4 and GCC 11.4.1-3 | 1.121 |=== +===== x64 Windows Results + +Run using an Intel i9-11900k chipset running Windows 11 and Visual Studio 17.11.4 + +|=== +| Type | Runtime (us) | Ratio to `double` +| `float` +| 4,734,517 +| 0.970 +| `double` +| 4,880,384 +| 1.000 +| `decimal32` +| 3,879,496 +| 0.795 +| `decimal64` +| 5,614,452 +| 1.150 +| `decimal32_fast` +| 4,445,619 +| 0.911 +| `decimal64_fast` +| 7,375,520 +| 1.511 +|=== + ===== M1 macOS Results Run using a Macbook pro with M1 pro chipset running macOS Sonoma 15.0 and homebrew GCC 14.2.0 From 2b3bbb14fa3aecbb2b3bb8709de65ceb54e94d83 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 14:05:30 -0400 Subject: [PATCH 67/77] Add the examples to the test battery --- test/Jamfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/Jamfile b/test/Jamfile index 0ef7e88eb..1189371d2 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -144,3 +144,10 @@ run test_tgamma.cpp ; run test_to_chars.cpp ; run test_to_string.cpp ; run test_zeta.cpp ; + +# Run the examples too +run ../examples/adl.cpp ; +run ../examples/basic_construction.cpp ; +run ../examples/charconv.cpp ; +run ../examples/literals.cpp ; +run ../examples/rounding_mode.cpp ; From d844e8d20a43a43f4558caf68e00ab2519d67249 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 14:20:15 -0400 Subject: [PATCH 68/77] Add example of the bit conversions --- examples/bit_conversions.cpp | 25 +++++++++++++++++++++++++ test/Jamfile | 1 + 2 files changed, 26 insertions(+) create mode 100644 examples/bit_conversions.cpp diff --git a/examples/bit_conversions.cpp b/examples/bit_conversions.cpp new file mode 100644 index 000000000..6893166e4 --- /dev/null +++ b/examples/bit_conversions.cpp @@ -0,0 +1,25 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::decimal; + +int main() +{ + const decimal32_fast fast_type {5}; + const std::uint32_t BID_bits {to_bid(fast_type)}; + const std::uint32_t DPD_bits {to_dpd(fast_type)}; + + std::cout << std::hex + << "BID format: " << BID_bits << '\n' + << "DPD format: " << DPD_bits << std::endl; + + const decimal32 bid_decimal {from_bid(BID_bits)}; + const decimal32 dpd_decimal {from_dpd(DPD_bits)}; + + return !(bid_decimal == dpd_decimal); +} diff --git a/test/Jamfile b/test/Jamfile index 1189371d2..17470c929 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -148,6 +148,7 @@ run test_zeta.cpp ; # Run the examples too run ../examples/adl.cpp ; run ../examples/basic_construction.cpp ; +run ../examples/bit_conversions.cpp ; run ../examples/charconv.cpp ; run ../examples/literals.cpp ; run ../examples/rounding_mode.cpp ; From cccf67b55bc78040440ad2863f1a9f2aa1935934 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 14:22:23 -0400 Subject: [PATCH 69/77] Add conversion example to docs --- doc/decimal/conversions.adoc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index 82ee90ae3..d1eea50b5 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -112,3 +112,34 @@ constexpr T from_dpd(unsigned __int128 bits) noexcept; } // namespace decimal } // namespace boost ---- + +Example +[source, c++] +---- +#include +#include +#include + +using namespace boost::decimal; + +int main() +{ + const decimal32_fast fast_type {5}; + const std::uint32_t BID_bits {to_bid(fast_type)}; + const std::uint32_t DPD_bits {to_dpd(fast_type)}; + + std::cout << std::hex + << "BID format: " << BID_bits << '\n' + << "DPD format: " << DPD_bits << std::endl; + + const decimal32 bid_decimal {from_bid(BID_bits)}; + const decimal32 dpd_decimal {from_dpd(DPD_bits)}; + + return !(bid_decimal == dpd_decimal); +} +---- +Output: +---- +BID format: 31fc4b40 +DPD format: 35f00000 +---- From 5b863764e57f5ee08d667bf013afe6638e9e4a30 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 14:23:11 -0400 Subject: [PATCH 70/77] Move location --- doc/decimal/conversions.adoc | 31 ------------------------------- doc/decimal/examples.adoc | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/doc/decimal/conversions.adoc b/doc/decimal/conversions.adoc index d1eea50b5..82ee90ae3 100644 --- a/doc/decimal/conversions.adoc +++ b/doc/decimal/conversions.adoc @@ -112,34 +112,3 @@ constexpr T from_dpd(unsigned __int128 bits) noexcept; } // namespace decimal } // namespace boost ---- - -Example -[source, c++] ----- -#include -#include -#include - -using namespace boost::decimal; - -int main() -{ - const decimal32_fast fast_type {5}; - const std::uint32_t BID_bits {to_bid(fast_type)}; - const std::uint32_t DPD_bits {to_dpd(fast_type)}; - - std::cout << std::hex - << "BID format: " << BID_bits << '\n' - << "DPD format: " << DPD_bits << std::endl; - - const decimal32 bid_decimal {from_bid(BID_bits)}; - const decimal32 dpd_decimal {from_dpd(DPD_bits)}; - - return !(bid_decimal == dpd_decimal); -} ----- -Output: ----- -BID format: 31fc4b40 -DPD format: 35f00000 ----- diff --git a/doc/decimal/examples.adoc b/doc/decimal/examples.adoc index fdee4e150..f812303ec 100644 --- a/doc/decimal/examples.adoc +++ b/doc/decimal/examples.adoc @@ -179,3 +179,35 @@ int main() return 0; } ---- + +== Bit Conversions +[source, c++] +---- +#include +#include +#include + +using namespace boost::decimal; + +int main() +{ + const decimal32_fast fast_type {5}; + const std::uint32_t BID_bits {to_bid(fast_type)}; + const std::uint32_t DPD_bits {to_dpd(fast_type)}; + + std::cout << std::hex + << "BID format: " << BID_bits << '\n' + << "DPD format: " << DPD_bits << std::endl; + + const decimal32 bid_decimal {from_bid(BID_bits)}; + const decimal32 dpd_decimal {from_dpd(DPD_bits)}; + + return !(bid_decimal == dpd_decimal); +} +---- +Output: +---- +BID format: 31fc4b40 +DPD format: 35f00000 +---- + From 2aa98c4a21ddccdf27fd91708ae52e60faf640d1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 14:38:11 -0400 Subject: [PATCH 71/77] Update charconv example --- doc/decimal/examples.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/decimal/examples.adoc b/doc/decimal/examples.adoc index f812303ec..167a5c225 100644 --- a/doc/decimal/examples.adoc +++ b/doc/decimal/examples.adoc @@ -92,6 +92,12 @@ int main() return 0; } ---- +Output: +---- + Initial Value: 0.25 +Returned Value: 0.25 +---- + == Rounding Mode [source, c++] From 487e1051da6612bc2fcccd22dcbb989bd6cd1fd3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 15:27:15 -0400 Subject: [PATCH 72/77] Improve maybe_unused definition --- include/boost/decimal/detail/config.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 4fc468466..7507557a8 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -172,10 +172,16 @@ typedef unsigned __int128 uint128_t; #define BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION -#if defined(___GNUC__) || defined(__clang__) -# define BOOST_DECIMAL_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#if __has_cpp_attribute(maybe_unused) +# define BOOST_DECIMAL_ATTRIBUTE_UNUSED [[maybe_unused]] #else -# define BOOST_DECIMAL_ATTRIBUTE_UNUSED +# if defined(___GNUC__) || defined(__clang__) +# define BOOST_DECIMAL_ATTRIBUTE_UNUSED __attribute__((__unused__)) +# elif defined(_MSC_VER) +# define BOOST_DECIMAL_ATTRIBUTE_UNUSED __pragma(warning(suppress: 4189)) +# else +# define BOOST_DECIMAL_ATTRIBUTE_UNUSED +# endif #endif #if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606L) From a814570787a4ec993a6e689e03f0b56f25438f5b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 15:27:21 -0400 Subject: [PATCH 73/77] Fix errors in examples --- examples/charconv.cpp | 2 +- examples/rounding_mode.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/charconv.cpp b/examples/charconv.cpp index 867b55a62..d79df3ec3 100644 --- a/examples/charconv.cpp +++ b/examples/charconv.cpp @@ -18,7 +18,7 @@ int main() *r_to.ptr = '\0'; decimal64 return_value; - auto r_from = from_chars(buffer, buffer + std::strlen(buffer), return_value); + BOOST_DECIMAL_ATTRIBUTE_UNUSED auto r_from = from_chars(buffer, buffer + std::strlen(buffer), return_value); assert(r_from); assert(val == return_value); diff --git a/examples/rounding_mode.cpp b/examples/rounding_mode.cpp index a994f36ad..63b79b937 100644 --- a/examples/rounding_mode.cpp +++ b/examples/rounding_mode.cpp @@ -7,9 +7,9 @@ int main() { - auto default_rounding_mode = boost::decimal::fegetround(); // Default is fe_dec_to_nearest_from_zero + BOOST_DECIMAL_ATTRIBUTE_UNUSED auto default_rounding_mode = boost::decimal::fegetround(); // Default is fe_dec_to_nearest_from_zero - auto new_rounding_mode = boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_to_nearest); + BOOST_DECIMAL_ATTRIBUTE_UNUSED auto new_rounding_mode = boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_to_nearest); assert(default_rounding_mode != new_rounding_mode); From 6868405bc05bcf893c6797d6ed6320da98f92d7b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 1 Oct 2024 16:40:57 -0400 Subject: [PATCH 74/77] Fix clang error --- examples/literals.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/literals.cpp b/examples/literals.cpp index 6361e26ff..3f6195421 100644 --- a/examples/literals.cpp +++ b/examples/literals.cpp @@ -17,8 +17,8 @@ int main() { using namespace boost::decimal; - const auto pi_32 {"3.141592653589793238"_DF}; - const auto pi_64 {"3.141592653589793238"_DD}; + BOOST_DECIMAL_ATTRIBUTE_UNUSED const auto pi_32 {"3.141592653589793238"_DF}; + BOOST_DECIMAL_ATTRIBUTE_UNUSED const auto pi_64 {"3.141592653589793238"_DD}; assert(float_equal(pi_32, static_cast(pi_64))); // Explicit conversion between decimal types assert(float_equal(pi_32, boost::decimal::numbers::pi_v)); // Constants available in numbers namespace From dfabd0fda34a87d53db4be0b4bcbfed791313141 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 16:46:15 -0400 Subject: [PATCH 75/77] Remove maybe unused attribute from static constexpr member variables --- include/boost/decimal/decimal128.hpp | 64 ++++++++++---------- include/boost/decimal/decimal128_fast.hpp | 64 ++++++++++---------- include/boost/decimal/decimal32.hpp | 64 ++++++++++---------- include/boost/decimal/decimal32_fast.hpp | 64 ++++++++++---------- include/boost/decimal/decimal64.hpp | 64 ++++++++++---------- include/boost/decimal/decimal64_fast.hpp | 64 ++++++++++---------- include/boost/decimal/detail/emulated128.hpp | 64 ++++++++++---------- 7 files changed, 224 insertions(+), 224 deletions(-) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index e3143e06d..1da9b031b 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -2187,45 +2187,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + 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))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 34; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -6142; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 6145; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 34; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -6142; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 6145; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::decimal128 { return {1, min_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent, true}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::decimal128 { return {1, -34}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::decimal128 { return epsilon(); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_inf_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_nan_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_snan_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::decimal128 { return {1, boost::decimal::detail::etiny_v}; } + static constexpr auto (min) () -> boost::decimal::decimal128 { return {1, min_exponent}; } + static constexpr auto (max) () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent}; } + static constexpr auto lowest () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent, true}; } + static constexpr auto epsilon () -> boost::decimal::decimal128 { return {1, -34}; } + static constexpr auto round_error () -> boost::decimal::decimal128 { return epsilon(); } + static constexpr auto infinity () -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_inf_mask); } + static constexpr auto quiet_NaN () -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_nan_mask); } + static constexpr auto signaling_NaN() -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_snan_mask); } + static constexpr auto denorm_min () -> boost::decimal::decimal128 { return {1, boost::decimal::detail::etiny_v}; } }; } //namespace std diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 4d1de7f27..655669f95 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -1428,45 +1428,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + 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))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 34; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -6142; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 6145; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + 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 = 34; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -6142; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 6145; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::decimal128_fast { return {1, min_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent, true}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::decimal128_fast { return {1, -34}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::decimal128_fast { return epsilon(); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_inf, 0, false); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_qnan, 0, false); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_snan, 0, false); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::decimal128_fast { return {1, boost::decimal::detail::etiny_v}; } + static constexpr auto (min) () -> boost::decimal::decimal128_fast { return {1, min_exponent}; } + static constexpr auto (max) () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent}; } + static constexpr auto lowest () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent, true}; } + static constexpr auto epsilon () -> boost::decimal::decimal128_fast { return {1, -34}; } + static constexpr auto round_error () -> boost::decimal::decimal128_fast { return epsilon(); } + static constexpr auto infinity () -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_inf, 0, false); } + static constexpr auto quiet_NaN () -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_qnan, 0, false); } + static constexpr auto signaling_NaN() -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_snan, 0, false); } + static constexpr auto denorm_min () -> boost::decimal::decimal128_fast { return {1, boost::decimal::detail::etiny_v}; } }; } diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 26370367f..00accccdd 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -2202,45 +2202,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + 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))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 7; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -95; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 96; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 7; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -95; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 96; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::decimal32 { return {1, min_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::decimal32 { return {9'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::decimal32 { return {-9'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::decimal32 { return {1, -7}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::decimal32 { return epsilon(); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_inf_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_nan_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_snan_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::decimal32 { return {1, boost::decimal::detail::etiny}; } + static constexpr auto (min) () -> boost::decimal::decimal32 { return {1, min_exponent}; } + static constexpr auto (max) () -> boost::decimal::decimal32 { return {9'999'999, max_exponent}; } + static constexpr auto lowest () -> boost::decimal::decimal32 { return {-9'999'999, max_exponent}; } + static constexpr auto epsilon () -> boost::decimal::decimal32 { return {1, -7}; } + static constexpr auto round_error () -> boost::decimal::decimal32 { return epsilon(); } + static constexpr auto infinity () -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_inf_mask); } + static constexpr auto quiet_NaN () -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_nan_mask); } + static constexpr auto signaling_NaN() -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_snan_mask); } + static constexpr auto denorm_min () -> boost::decimal::decimal32 { return {1, boost::decimal::detail::etiny}; } }; } // Namespace std diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 48f5881bb..348e84dcd 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -1438,47 +1438,47 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + 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))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_absent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = false; + static constexpr std::float_denorm_style has_denorm = std::denorm_absent; + static constexpr bool has_denorm_loss = false; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 7; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -95; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 96; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + 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 = 7; + static constexpr int digits10 = digits; + static constexpr int max_digits10 = digits; + static constexpr int radix = 10; + static constexpr int min_exponent = -95; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 96; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::decimal32_fast { return {1, min_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::decimal32_fast { return {9'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::decimal32_fast { return {-9'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::decimal32_fast { return {1, -7}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::decimal32_fast { return epsilon(); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_inf, UINT8_C((0))); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_qnan, UINT8_C((0))); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_snan, UINT8_C((0))); } + static constexpr auto (min) () -> boost::decimal::decimal32_fast { return {1, min_exponent}; } + static constexpr auto (max) () -> boost::decimal::decimal32_fast { return {9'999'999, max_exponent}; } + static constexpr auto lowest () -> boost::decimal::decimal32_fast { return {-9'999'999, max_exponent}; } + static constexpr auto epsilon () -> boost::decimal::decimal32_fast { return {1, -7}; } + static constexpr auto round_error () -> boost::decimal::decimal32_fast { return epsilon(); } + static constexpr auto infinity () -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_inf, UINT8_C((0))); } + static constexpr auto quiet_NaN () -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_qnan, UINT8_C((0))); } + static constexpr auto signaling_NaN() -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_snan, UINT8_C((0))); } // With denorm absent returns the same value as min - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::decimal32_fast { return {1, min_exponent}; } + static constexpr auto denorm_min () -> boost::decimal::decimal32_fast { return {1, min_exponent}; } }; } // Namespace std diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 2341865a5..95df42edd 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -2099,45 +2099,45 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + 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))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 16; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -382; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 385; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = true; + 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 = -382; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 385; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::decimal64 { return {1, min_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::decimal64 { return {9'999'999'999'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::decimal64 { return {-9'999'999'999'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::decimal64 { return {1, -16}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::decimal64 { return epsilon(); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_inf_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_nan_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_snan_mask); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::decimal64 { return {1, boost::decimal::detail::etiny_v}; } + static constexpr auto (min) () -> boost::decimal::decimal64 { return {1, min_exponent}; } + static constexpr auto (max) () -> boost::decimal::decimal64 { return {9'999'999'999'999'999, max_exponent}; } + static constexpr auto lowest () -> boost::decimal::decimal64 { return {-9'999'999'999'999'999, max_exponent}; } + static constexpr auto epsilon () -> boost::decimal::decimal64 { return {1, -16}; } + static constexpr auto round_error () -> boost::decimal::decimal64 { return epsilon(); } + static constexpr auto infinity () -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_inf_mask); } + static constexpr auto quiet_NaN () -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_nan_mask); } + static constexpr auto signaling_NaN() -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_snan_mask); } + static constexpr auto denorm_min () -> boost::decimal::decimal64 { return {1, boost::decimal::detail::etiny_v}; } }; } // Namespace std diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 09d862696..1d3742dbb 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1382,48 +1382,48 @@ struct numeric_limits public: #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = true; + 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))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_present; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = true; + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_indeterminate; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 16; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = digits; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 10; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = -382; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 385; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true; + 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 = -382; + static constexpr int min_exponent10 = min_exponent; + static constexpr int max_exponent = 385; + static constexpr int max_exponent10 = max_exponent; + static constexpr bool traps = numeric_limits::traps; + static constexpr bool tinyness_before = true; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::decimal64_fast { return {1, min_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::decimal64_fast { return {9'999'999'999'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::decimal64_fast { return {-9'999'999'999'999'999, max_exponent}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::decimal64_fast { return {1, -16}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::decimal64_fast { return epsilon(); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64( + static constexpr auto (min) () -> boost::decimal::decimal64_fast { return {1, min_exponent}; } + static constexpr auto (max) () -> boost::decimal::decimal64_fast { return {9'999'999'999'999'999, max_exponent}; } + static constexpr auto lowest () -> boost::decimal::decimal64_fast { return {-9'999'999'999'999'999, max_exponent}; } + static constexpr auto epsilon () -> boost::decimal::decimal64_fast { return {1, -16}; } + static constexpr auto round_error () -> boost::decimal::decimal64_fast { return epsilon(); } + static constexpr auto infinity () -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64( boost::decimal::detail::d64_fast_inf, 0, false); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64( + static constexpr auto quiet_NaN () -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64( boost::decimal::detail::d64_fast_qnan, 0, false); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64( + static constexpr auto signaling_NaN() -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64( boost::decimal::detail::d64_fast_snan, 0, false); } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::decimal64_fast { return {1, boost::decimal::detail::etiny_v}; } + static constexpr auto denorm_min () -> boost::decimal::decimal64_fast { return {1, boost::decimal::detail::etiny_v}; } }; } // namespace std diff --git a/include/boost/decimal/detail/emulated128.hpp b/include/boost/decimal/detail/emulated128.hpp index 574ebe585..b2c2d31e0 100644 --- a/include/boost/decimal/detail/emulated128.hpp +++ b/include/boost/decimal/detail/emulated128.hpp @@ -1342,45 +1342,45 @@ template <> struct numeric_limits { // Member constants - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_signed = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_integer = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_exact = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_infinity = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = false; + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; // These members were deprecated in C++23 #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_denorm_style has_denorm = std::denorm_absent; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool has_denorm_loss = false; + static constexpr std::float_denorm_style has_denorm = std::denorm_absent; + static constexpr bool has_denorm_loss = false; #endif - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_toward_zero; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool is_modulo = true; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits = 128; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int digits10 = 38; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_digits10 = 0; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int radix = 2; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent = 0; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = 0; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 0; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = 0; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = std::numeric_limits::traps; - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = false; + static constexpr std::float_round_style round_style = std::round_toward_zero; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 128; + static constexpr int digits10 = 38; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = false; // Member functions - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (min) () -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto lowest () -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto (max) () -> boost::decimal::detail::uint128 { return {UINT64_MAX, UINT64_MAX}; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto epsilon () -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto round_error () -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto infinity () -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto quiet_NaN () -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto signaling_NaN() -> boost::decimal::detail::uint128 { return 0; } - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr auto denorm_min () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto (min) () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto lowest () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto (max) () -> boost::decimal::detail::uint128 { return {UINT64_MAX, UINT64_MAX}; } + static constexpr auto epsilon () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto round_error () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto infinity () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto quiet_NaN () -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto signaling_NaN() -> boost::decimal::detail::uint128 { return 0; } + static constexpr auto denorm_min () -> boost::decimal::detail::uint128 { return 0; } }; } // namespace std From 58ee813b08d0b8a4888459612442b7971aa4545a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 2 Oct 2024 17:14:00 -0400 Subject: [PATCH 76/77] Remove non-functional pragmas --- test/benchmarks.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/benchmarks.cpp b/test/benchmarks.cpp index c261fcdf0..59a1ebbf8 100644 --- a/test/benchmarks.cpp +++ b/test/benchmarks.cpp @@ -3,12 +3,6 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#if defined(__GNUC__) && __GNUC__ > 5 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wclass-memaccess" -# pragma GCC diagnostic ignored "-Warray-bounds" -#endif - #include #include #include From e39e572bc3cc1b177373fcd62bbed6a18c08ce7c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 3 Oct 2024 10:23:31 -0400 Subject: [PATCH 77/77] Remove uneeded attribute in Charconv --- include/boost/decimal/charconv.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 001c76d28..1ad74ea85 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -914,12 +914,12 @@ BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* la template struct limits { - BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_chars = boost::decimal::detail::max_string_length_v; + static constexpr int max_chars = boost::decimal::detail::max_string_length_v; }; #if !(defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L) && (!defined(_MSC_VER) || _MSC_VER != 1900) -template BOOST_DECIMAL_ATTRIBUTE_UNUSED constexpr int limits::max_chars; +template constexpr int limits::max_chars; #endif