From 7c64ba4fa925f34569634c7920217a4bb9fb545c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 31 Jan 2025 09:27:05 -0500 Subject: [PATCH 01/11] Use fixed width instead of fast types --- include/boost/decimal/decimal128_fast.hpp | 6 +++--- include/boost/decimal/decimal32_fast.hpp | 6 +++--- include/boost/decimal/decimal64_fast.hpp | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 520c53ac0..3d89f3a47 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -41,7 +41,7 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_snan_high_bits = UINT64_MAX; struct decimal128_fast_components { using significand_type = uint128; - using biased_exponent_type = std::int_fast32_t; + using biased_exponent_type = std::int32_t; significand_type sig; biased_exponent_type exp; @@ -54,8 +54,8 @@ BOOST_DECIMAL_EXPORT class decimal128_fast final { public: using significand_type = detail::uint128; - using exponent_type = std::uint_fast32_t; - using biased_exponent_type = std::int_fast32_t; + using exponent_type = std::uint32_t; + using biased_exponent_type = std::int32_t; private: // Instead of having to encode and decode at every operation diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 8e5b2304d..615e19539 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -37,9 +37,9 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits Date: Fri, 31 Jan 2025 09:27:17 -0500 Subject: [PATCH 02/11] Make exp type more consistent --- include/boost/decimal/decimal128.hpp | 2 +- include/boost/decimal/decimal64.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index 669020b8d..280042268 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -155,7 +155,7 @@ BOOST_DECIMAL_EXPORT class decimal128 final { public: using significand_type = detail::uint128; - using exponent_type = std::uint64_t; + using exponent_type = std::uint32_t; using biased_exponent_type = std::int32_t; private: diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 19e089921..7b8748f8b 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -142,7 +142,7 @@ BOOST_DECIMAL_EXPORT class decimal64 final { public: using significand_type = std::uint64_t; - using exponent_type = std::uint64_t; + using exponent_type = std::uint32_t; using biased_exponent_type = std::int32_t; private: From 42571b94b39d6a2c1dacc73c0887fe3c5cf708b6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 31 Jan 2025 09:27:46 -0500 Subject: [PATCH 03/11] Document the typedefs --- doc/decimal/decimal128.adoc | 5 +++++ doc/decimal/decimal128_fast.adoc | 5 +++++ doc/decimal/decimal32.adoc | 5 +++++ doc/decimal/decimal32_fast.adoc | 7 ++++++- doc/decimal/decimal64.adoc | 5 +++++ doc/decimal/decimal64_fast.adoc | 7 ++++++- 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/doc/decimal/decimal128.adoc b/doc/decimal/decimal128.adoc index a6b2c3d20..8a5dd713c 100644 --- a/doc/decimal/decimal128.adoc +++ b/doc/decimal/decimal128.adoc @@ -30,6 +30,11 @@ namespace decimal { class decimal128 { +public: + using significand_type = detail::uint128; + using exponent_type = std::uint32_t; + using biased_exponent_type = std::int32_t; + // Paragraph numbers are from ISO/IEC DTR 24733 // 3.2.4.1 construct/copy/destroy diff --git a/doc/decimal/decimal128_fast.adoc b/doc/decimal/decimal128_fast.adoc index 0c39b529c..860105e4c 100644 --- a/doc/decimal/decimal128_fast.adoc +++ b/doc/decimal/decimal128_fast.adoc @@ -30,6 +30,11 @@ namespace decimal { class decimal128_fast { +public: + using significand_type = detail::uint128; + using exponent_type = std::uint32_t; + using biased_exponent_type = std::int32_t; + // Paragraph numbers are from ISO/IEC DTR 24733 // 3.2.4.1 construct/copy/destroy diff --git a/doc/decimal/decimal32.adoc b/doc/decimal/decimal32.adoc index 2fd48eac4..d65ba1854 100644 --- a/doc/decimal/decimal32.adoc +++ b/doc/decimal/decimal32.adoc @@ -30,6 +30,11 @@ namespace decimal { class decimal32 { +public: + using significand_type = std::uint32_t; + using exponent_type = std::uint32_t; + using biased_exponent_type = std::int32_t; + // Paragraph numbers are from ISO/IEC DTR 24733 // 3.2.2.1 construct/copy/destroy diff --git a/doc/decimal/decimal32_fast.adoc b/doc/decimal/decimal32_fast.adoc index 307c9e81d..3649e6cbe 100644 --- a/doc/decimal/decimal32_fast.adoc +++ b/doc/decimal/decimal32_fast.adoc @@ -14,7 +14,7 @@ https://www.boost.org/LICENSE_1_0.txt The performance changes by being non-IEEE 754 compliant so that the value does not have to be decoded from bits, but is instead directly represented internal to the type. As is often the case this trades space for time by having greater storage width requirements. -- Storage width - At least 48bits (`std::uint_fast32_t` + `std::uint_fast8_t` + `bool`) +- Storage width - 48bits (`std::uint32_t` + `std::uint8_t` + `bool`) - Precision - 7 decimal digits (not bits like binary) - Max exponent - 96 - Max Value - 9.999999e96 @@ -30,6 +30,11 @@ namespace decimal { class decimal32_fast { +public: + using significand_type = std::uint32_t; + using exponent_type = std::uint8_t; + using biased_exponent_type = std::int32_t; + // Paragraph numbers are from ISO/IEC DTR 24733 // 3.2.2.1 construct/copy/destroy diff --git a/doc/decimal/decimal64.adoc b/doc/decimal/decimal64.adoc index 08dd83f02..c6c18316d 100644 --- a/doc/decimal/decimal64.adoc +++ b/doc/decimal/decimal64.adoc @@ -30,6 +30,11 @@ namespace decimal { class decimal64 { +public: + using significand_type = std::uint64_t; + using exponent_type = std::uint32_t; + using biased_exponent_type = std::int32_t; + // Paragraph numbers are from ISO/IEC DTR 24733 // 3.2.3.1 construct/copy/destroy diff --git a/doc/decimal/decimal64_fast.adoc b/doc/decimal/decimal64_fast.adoc index 417a22ad4..9393f2b98 100644 --- a/doc/decimal/decimal64_fast.adoc +++ b/doc/decimal/decimal64_fast.adoc @@ -14,7 +14,7 @@ https://www.boost.org/LICENSE_1_0.txt The performance changes by being non-IEEE 754 compliant so that the value does not have to be decoded from bits, but is instead directly represented internal to the type. As is often the case this trades space for time by having greater storage width requirements. -- Storage width - At least 88 bits (`std::uint_fast64_t` + `std::uint_fast_16_t` + `bool`) +- Storage width - 88 bits (`std::uint64_t` + `std::uint16_t` + `bool`) - Precision - 16 decimal digits (not bits like binary) - Max exponent - 385 - Max Value - 9.999999999999999e385 @@ -30,6 +30,11 @@ namespace decimal { class decimal64_fast { +public: + using significand_type = std::uint64_t; + using exponent_type = std::uint16_t; + using biased_exponent_type = std::int32_t; + // Paragraph numbers are from ISO/IEC DTR 24733 // 3.2.3.1 construct/copy/destroy From c6d6b32b77f581adc5010b079533810e9b60cc75 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 31 Jan 2025 15:22:56 -0500 Subject: [PATCH 04/11] Fix types of non-finite values masks --- include/boost/decimal/decimal32_fast.hpp | 6 +++--- include/boost/decimal/decimal64_fast.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 615e19539..a037b41f6 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -28,9 +28,9 @@ namespace decimal { namespace detail { -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_inf = std::numeric_limits::max() - 3; -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_qnan = std::numeric_limits::max() - 2; -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits::max() - 1; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_fast_inf = std::numeric_limits::max() - 3; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_fast_qnan = std::numeric_limits::max() - 2; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_fast_snan = std::numeric_limits::max() - 1; } diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 75e671cdf..e8269cffa 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -31,9 +31,9 @@ namespace decimal { namespace detail { -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d64_fast_inf = std::numeric_limits::max() - 3; -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d64_fast_qnan = std::numeric_limits::max() - 2; -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d64_fast_snan = std::numeric_limits::max() - 1; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d64_fast_inf = std::numeric_limits::max() - 3; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d64_fast_qnan = std::numeric_limits::max() - 2; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d64_fast_snan = std::numeric_limits::max() - 1; struct decimal64_fast_components { From dc3a369bd065ed41412ff8b31b142bd5788ac7ef Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 10 Feb 2025 10:54:37 -0500 Subject: [PATCH 05/11] Fix conversion ambiguity --- include/boost/decimal/decimal32_fast.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index a037b41f6..bc44f3d66 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -837,9 +837,9 @@ constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept exp_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - const auto final_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; + const auto final_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; - return detail::d32_add_impl(lhs.significand_, lhs.biased_exponent(), lhs.sign_, + return detail::d32_add_impl(static_cast(lhs.significand_), lhs.biased_exponent(), lhs.sign_, final_sig_rhs, exp_rhs, (rhs < 0), abs_lhs_bigger); } From ccaa9a7a716279eb606688cb5af08d63dfcd6af5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 10 Feb 2025 10:57:19 -0500 Subject: [PATCH 06/11] Fix decimal32_fast components type --- include/boost/decimal/detail/components.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/components.hpp b/include/boost/decimal/detail/components.hpp index 5b6738e0f..3766f77d2 100644 --- a/include/boost/decimal/detail/components.hpp +++ b/include/boost/decimal/detail/components.hpp @@ -27,8 +27,8 @@ struct decimal32_components struct decimal32_fast_components { - using significand_type = std::uint_fast32_t; - using biased_exponent_type = std::int_fast32_t; + using significand_type = std::uint32_t; + using biased_exponent_type = std::int32_t; significand_type sig; biased_exponent_type exp; From 109fe6912fcf54b12309f04b5887fb451cbaeacf Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 10 Feb 2025 12:04:40 -0500 Subject: [PATCH 07/11] Fix more naked usage fast types --- include/boost/decimal/decimal32_fast.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index bc44f3d66..2ba6177d1 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -326,7 +326,7 @@ BOOST_DECIMAL_EXPORT class decimal32_fast final template && (detail::impl::decimal_val_v <= detail::impl::decimal_val_v), bool> = true> explicit constexpr operator Decimal() const noexcept; - friend constexpr auto direct_init(std::uint_fast32_t significand, std::uint_fast8_t exponent, bool sign) noexcept -> decimal32_fast; + friend constexpr auto direct_init(significand_type significand, exponent_type exponent, bool sign) noexcept -> decimal32_fast; // or extensions that need to be friends template @@ -379,7 +379,7 @@ constexpr decimal32_fast::decimal32_fast(T1 coeff, T2 exp, bool sign) noexcept exp = 0; } - auto biased_exp {static_cast(exp + detail::bias)}; + auto biased_exp {static_cast(exp + detail::bias)}; // Decimal32 exponent holds 8 bits if (biased_exp > detail::max_biased_exp_v) @@ -431,7 +431,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR decimal32_fast::decimal32_fast(Float val) noexcept # pragma GCC diagnostic pop #endif -constexpr auto direct_init(std::uint_fast32_t significand, std::uint_fast8_t exponent, bool sign = false) noexcept -> decimal32_fast +constexpr auto direct_init(decimal32_fast::significand_type significand, decimal32_fast::exponent_type exponent, bool sign = false) noexcept -> decimal32_fast { decimal32_fast val; val.significand_ = significand; @@ -1028,11 +1028,13 @@ constexpr auto div_impl(decimal32_fast lhs, decimal32_fast rhs, decimal32_fast& << "\nexp rhs: " << exp_rhs << std::endl; #endif + using promoted_type = std::uint64_t; + // We promote to uint64 since the significands are currently 32-bits // By appending enough zeros to the LHS we end up finding what we need anyway - constexpr auto ten_pow_precision {detail::pow10(static_cast(detail::precision_v))}; - const auto big_sig_lhs {static_cast(lhs.significand_) * ten_pow_precision}; - const auto res_sig {big_sig_lhs / static_cast(rhs.significand_)}; + constexpr auto ten_pow_precision {detail::pow10(static_cast(detail::precision_v))}; + const auto big_sig_lhs {static_cast(lhs.significand_) * ten_pow_precision}; + const auto res_sig {big_sig_lhs / static_cast(rhs.significand_)}; const auto res_exp {(lhs.biased_exponent() - detail::precision_v) - rhs.biased_exponent()}; q = decimal32_fast(res_sig, res_exp, lhs.sign_ != rhs.sign_); @@ -1500,7 +1502,7 @@ struct numeric_limits 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 traps = numeric_limits::traps; static constexpr bool tinyness_before = true; // Member functions From c49ad07d8287121fefe66f2ed71ceeaa50495210 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 10 Feb 2025 13:27:27 -0500 Subject: [PATCH 08/11] Check for unsigned rollover --- include/boost/decimal/decimal32_fast.hpp | 2 +- include/boost/decimal/decimal64_fast.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 2ba6177d1..49546fe5f 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -382,7 +382,7 @@ constexpr decimal32_fast::decimal32_fast(T1 coeff, T2 exp, bool sign) noexcept auto biased_exp {static_cast(exp + detail::bias)}; // Decimal32 exponent holds 8 bits - if (biased_exp > detail::max_biased_exp_v) + if (biased_exp > detail::max_biased_exp_v || exp > detail::max_biased_exp_v) { significand_ = detail::d32_fast_inf; } diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index e8269cffa..ce1b466e3 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -390,9 +390,9 @@ constexpr decimal64_fast::decimal64_fast(T1 coeff, T2 exp, bool sign) noexcept exp = 0; } - const auto biased_exp {static_cast(exp + detail::bias_v)}; + const auto biased_exp {static_cast(exp + detail::bias_v)}; - if (biased_exp > detail::max_biased_exp_v) + if (biased_exp > detail::max_biased_exp_v || exp > detail::max_biased_exp_v) { significand_ = detail::d64_fast_inf; } From ab556d2f01cfa1fa496f9ee263fd7aaeff14b608 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 10 Feb 2025 14:31:14 -0500 Subject: [PATCH 09/11] Fix GCC conversion warning --- include/boost/decimal/decimal64.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 7b8748f8b..0817fef8d 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1018,7 +1018,7 @@ constexpr auto decimal64::unbiased_exponent() const noexcept -> exponent_type break; } - expval |= (bits_ & detail::d64_exponent_mask) >> detail::d64_significand_bits; + expval |= static_cast((bits_ & detail::d64_exponent_mask) >> detail::d64_significand_bits); return expval; } From aae50cd8e86eaf78d21196b64cfd16fc0e95da77 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 10 Feb 2025 14:31:27 -0500 Subject: [PATCH 10/11] Fix possible loss of exp --- include/boost/decimal/decimal32_fast.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 49546fe5f..84bb402ac 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -379,7 +379,7 @@ constexpr decimal32_fast::decimal32_fast(T1 coeff, T2 exp, bool sign) noexcept exp = 0; } - auto biased_exp {static_cast(exp + detail::bias)}; + auto biased_exp {static_cast(exp + detail::bias)}; // Decimal32 exponent holds 8 bits if (biased_exp > detail::max_biased_exp_v || exp > detail::max_biased_exp_v) @@ -1028,7 +1028,7 @@ constexpr auto div_impl(decimal32_fast lhs, decimal32_fast rhs, decimal32_fast& << "\nexp rhs: " << exp_rhs << std::endl; #endif - using promoted_type = std::uint64_t; + using promoted_type = std::uint_fast64_t; // We promote to uint64 since the significands are currently 32-bits // By appending enough zeros to the LHS we end up finding what we need anyway From 706e58eecedf75f622ac680b6eeed2ae45557c10 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 11 Feb 2025 12:22:29 -0500 Subject: [PATCH 11/11] Fix possible promotion issues for ancient clang toolchains --- include/boost/decimal/decimal32_fast.hpp | 4 ++-- include/boost/decimal/detail/promote_significand.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 84bb402ac..68e6da8d3 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -379,7 +379,7 @@ constexpr decimal32_fast::decimal32_fast(T1 coeff, T2 exp, bool sign) noexcept exp = 0; } - auto biased_exp {static_cast(exp + detail::bias)}; + auto biased_exp {static_cast(exp + detail::bias)}; // Decimal32 exponent holds 8 bits if (biased_exp > detail::max_biased_exp_v || exp > detail::max_biased_exp_v) @@ -1028,7 +1028,7 @@ constexpr auto div_impl(decimal32_fast lhs, decimal32_fast rhs, decimal32_fast& << "\nexp rhs: " << exp_rhs << std::endl; #endif - using promoted_type = std::uint_fast64_t; + using promoted_type = std::uint64_t; // We promote to uint64 since the significands are currently 32-bits // By appending enough zeros to the LHS we end up finding what we need anyway diff --git a/include/boost/decimal/detail/promote_significand.hpp b/include/boost/decimal/detail/promote_significand.hpp index b53149d37..3a0e57f55 100644 --- a/include/boost/decimal/detail/promote_significand.hpp +++ b/include/boost/decimal/detail/promote_significand.hpp @@ -19,7 +19,7 @@ namespace impl { template struct promote_significand { - using type = std::conditional_t::digits10 < std::numeric_limits::digits10, + using type = std::conditional_t>::digits10 < std::numeric_limits::digits10, typename DecimalType::significand_type, detail::make_unsigned_t>; };