From 64bb230dfa4c3b5cc23e504ea946f8465b10f258 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 16:03:54 -0500 Subject: [PATCH 01/55] Add definition of [[nodiscard]] --- include/boost/decimal/detail/config.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 02ad865c..7cb5ba9c 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -341,6 +341,16 @@ typedef unsigned __int128 uint128_t; # endif # endif +#ifdef __has_cpp_attribute +# if __has_cpp_attribute(nodiscard) +# define BOOST_DECIMAL_NO_DISCARD [[nodiscard]] +# endif +#endif + +#ifndef BOOST_DECIMAL_NO_DISCARD +# define BOOST_DECIMAL_NO_DISCARD +#endif + #endif // Since we should not be able to pull these in from the STL in module mode define them ourselves From a3a0e70d9b7e953f894a48f75007dc415d8e1d75 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 16:38:25 -0500 Subject: [PATCH 02/55] Add framework and accessors of a gcc_decimal32 wrapper --- include/boost/decimal/gcc_decimal32.hpp | 170 ++++++++++++++++++++++++ test/Jamfile | 1 + test/compile_tests/gcc_decimal32.cpp | 21 +++ 3 files changed, 192 insertions(+) create mode 100644 include/boost/decimal/gcc_decimal32.hpp create mode 100644 test/compile_tests/gcc_decimal32.cpp diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp new file mode 100644 index 00000000..70a19578 --- /dev/null +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -0,0 +1,170 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_GCC_DECIMAL32_HPP +#define BOOST_DECIMAL_GCC_DECIMAL32_HPP + +#if __has_include() + +#include +#include +#include + +#ifndef BOOST_DECIMAL_BUILD_MODULE + +#include +#include + +#endif // BOOST_DECIMAL_BUILD_MODULE + +#define BOOST_DECIMAL_HAS_GCC_DECIMAL32 1 + +namespace boost { +namespace decimal { + +// This type is a wrapper around gcc std::decimal::decimal32 to allow it to use +// the standard library provided by Boost.Decimal +BOOST_DECIMAL_EXPORT class gcc_decimal32 final +{ +public: + using significand_type = std::uint32_t; + using exponent_type = std::uint32_t; + using biased_exponent_type = std::int32_t; + +private: + + std::decimal::decimal32 internal_decimal_ {}; + + // Returns the un-biased (quantum) exponent + BOOST_DECIMAL_NO_DISCARD inline auto unbiased_exponent() const noexcept -> exponent_type; + + // Returns the biased exponent + BOOST_DECIMAL_NO_DISCARD inline auto biased_exponent() const noexcept -> biased_exponent_type; + + // Returns the significand complete with the bits implied from the combination field + BOOST_DECIMAL_NO_DISCARD inline auto full_significand() const noexcept -> significand_type; + + BOOST_DECIMAL_NO_DISCARD inline auto isneg() const noexcept -> bool; + + // Since we have the overhead of memcpy in order to decode anything + // get them all at once if we are going to need it + BOOST_DECIMAL_NO_DISCARD inline auto to_components() const noexcept -> detail::decimal32_components; +}; + +namespace detail { + +BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_unbiased_exponent(std::uint32_t bits_) noexcept -> gcc_decimal32::exponent_type +{ + gcc_decimal32::exponent_type expval {}; + const auto exp_comb_bits {(bits_ & detail::d32_comb_11_mask)}; + + switch (exp_comb_bits) + { + case detail::d32_comb_11_mask: + // bits 2 and 3 are the exp part of the combination field + expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); + break; + case detail::d32_comb_10_mask: + expval = UINT32_C(0b10000000); + break; + case detail::d32_comb_01_mask: + expval = UINT32_C(0b01000000); + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + + expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; + + return expval; +} + +BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_biased_exponent(std::uint32_t bits) -> gcc_decimal32::biased_exponent_type +{ + return static_cast(decode_gccd32_unbiased_exponent(bits)) - detail::bias_v; +} + +BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_significand(std::uint32_t bits_) -> gcc_decimal32::significand_type +{ + gcc_decimal32::significand_type significand {}; + + if ((bits_ & detail::d32_comb_11_mask) == detail::d32_comb_11_mask) + { + // Only need the one bit of T because the other 3 are implied + significand = (bits_ & detail::d32_comb_11_significand_bits) == detail::d32_comb_11_significand_bits ? + UINT32_C(0b1001'0000000000'0000000000) : + UINT32_C(0b1000'0000000000'0000000000); + } + else + { + // Last three bits in the combination field, so we need to shift past the exp field + // which is next + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + } + + significand |= (bits_ & detail::d32_significand_mask); + + return significand; +} + +BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_sign(std::uint32_t bits_) -> bool +{ + return static_cast(bits_ & detail::d32_sign_mask); +} + +} // detail + +inline auto gcc_decimal32::unbiased_exponent() const noexcept -> exponent_type +{ + std::uint32_t bits_; + std::memcpy(&bits_, &internal_decimal_, sizeof(std::uint32_t)); + return detail::decode_gccd32_unbiased_exponent(bits_); +} + +inline auto gcc_decimal32::biased_exponent() const noexcept -> biased_exponent_type +{ + std::uint32_t bits_; + std::memcpy(&bits_, &internal_decimal_, sizeof(std::uint32_t)); + return detail::decode_gccd32_biased_exponent(bits_); +} + +inline auto gcc_decimal32::full_significand() const noexcept -> significand_type +{ + std::uint32_t bits_ {}; + std::memcpy(&bits_, &internal_decimal_, sizeof(std::uint32_t)); + return detail::decode_gccd32_significand(bits_); +} + +inline auto gcc_decimal32::isneg() const noexcept -> bool +{ + std::uint32_t bits_ {}; + std::memcpy(&bits_, &internal_decimal_, sizeof(std::uint32_t)); + return detail::decode_gccd32_sign(bits_); +} + +inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_components +{ + detail::decimal32_components components {}; + std::uint32_t bits_ {}; + std::memcpy(&bits_, &internal_decimal_, sizeof(std::uint32_t)); + + components.sig = detail::decode_gccd32_significand(bits_); + components.exp = detail::decode_gccd32_biased_exponent(bits_); + components.sign = detail::decode_gccd32_sign(bits_); + + return components; +} + +} // namespace decimal +} // namespace boost + +#else + +#error "libstdc++ header is required to use this functionality" + +#endif // __has_include() + +#endif // BOOST_DECIMAL_GCC_DECIMAL32_HPP diff --git a/test/Jamfile b/test/Jamfile index bca35bae..690206c7 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -190,3 +190,4 @@ compile compile_tests/literals_compile.cpp ; compile compile_tests/numbers_compile.cpp ; compile compile_tests/string_compile.cpp ; compile compile_tests/uint128.cpp ; +compile compile_tests/gcc_decimal32.cpp ; diff --git a/test/compile_tests/gcc_decimal32.cpp b/test/compile_tests/gcc_decimal32.cpp new file mode 100644 index 00000000..d680d28b --- /dev/null +++ b/test/compile_tests/gcc_decimal32.cpp @@ -0,0 +1,21 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#if defined(__GNUC__) && __GNUC__ >= 5 + +#include + +int main() +{ + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif From 80e75b75816941d4927d7713c5ec6e662a2c8ced Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 16:46:42 -0500 Subject: [PATCH 03/55] Add construction from and conversion to integers --- include/boost/decimal/gcc_decimal32.hpp | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 70a19578..d62aa477 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -50,6 +50,17 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final // Since we have the overhead of memcpy in order to decode anything // get them all at once if we are going to need it BOOST_DECIMAL_NO_DISCARD inline auto to_components() const noexcept -> detail::decimal32_components; + +public: + + gcc_decimal32() = default; + + // 3.2.5 Initialization from coefficient and exponent. + gcc_decimal32(long long coeff, int exp); + gcc_decimal32(unsigned long long coeff, int exp); + + // Non-conforming extension: Conversion to integral type. + inline operator long long() const noexcept; }; namespace detail { @@ -158,6 +169,21 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c return components; } +inline gcc_decimal32::gcc_decimal32(long long coeff, int exp) +{ + internal_decimal_ = std::decimal::make_decimal32(coeff, exp); +} + +inline gcc_decimal32::gcc_decimal32(unsigned long long coeff, int exp) +{ + internal_decimal_ = std::decimal::make_decimal32(coeff, exp); +} + +inline gcc_decimal32::operator long long() const noexcept +{ + return std::decimal::decimal32_to_long_long(internal_decimal_); +} + } // namespace decimal } // namespace boost From 6a824d9c564497d199b17a99df49729e51b77cf0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 17:20:36 -0500 Subject: [PATCH 04/55] Add conversion to float --- include/boost/decimal/gcc_decimal32.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index d62aa477..5c1375cc 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -61,6 +61,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final // Non-conforming extension: Conversion to integral type. inline operator long long() const noexcept; + + // 3.2.6 Conversion to generic floating-point type. + inline explicit operator float() const noexcept; + inline explicit operator double() const noexcept; + inline explicit operator long double() const noexcept; + }; namespace detail { @@ -184,6 +190,21 @@ inline gcc_decimal32::operator long long() const noexcept return std::decimal::decimal32_to_long_long(internal_decimal_); } +inline gcc_decimal32::operator float() const noexcept +{ + return std::decimal::decimal32_to_float(internal_decimal_); +} + +inline gcc_decimal32::operator double() const noexcept +{ + return std::decimal::decimal32_to_double(internal_decimal_); +} + +inline gcc_decimal32::operator long double() const noexcept +{ + return std::decimal::decimal32_to_long_double(internal_decimal_); +} + } // namespace decimal } // namespace boost From 713d53f21fbf3240faf1eecb7e1ec5c26f0a83ab Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 17:20:54 -0500 Subject: [PATCH 05/55] Add return type and underlying member function --- include/boost/decimal/gcc_decimal32.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 5c1375cc..7762db8d 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -51,8 +51,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final // get them all at once if we are going to need it BOOST_DECIMAL_NO_DISCARD inline auto to_components() const noexcept -> detail::decimal32_components; + BOOST_DECIMAL_NO_DISCARD inline auto underlying() const noexcept -> std::decimal::decimal32 { return internal_decimal_; } + public: + using return_type = std::decimal::decimal32; + gcc_decimal32() = default; // 3.2.5 Initialization from coefficient and exponent. From 0e957ee50eeb3d895c6480ea39f3ec061eca1cb3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 17:21:07 -0500 Subject: [PATCH 06/55] Add Unary operators --- include/boost/decimal/gcc_decimal32.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 7762db8d..92bfe086 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -71,6 +71,10 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final inline explicit operator double() const noexcept; inline explicit operator long double() const noexcept; + // 3.2.7 Unary arithmetic operators. + friend return_type operator+(const gcc_decimal32 rhs) { return rhs.underlying(); } + friend return_type operator-(const gcc_decimal32 rhs) { return -rhs.underlying(); } + }; namespace detail { From 6e1cfa150cb8a0bb5abff9f94ad61966c6a14373 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 17:21:17 -0500 Subject: [PATCH 07/55] Add binary operators --- include/boost/decimal/gcc_decimal32.hpp | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 92bfe086..ef8944e8 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -75,6 +75,46 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final friend return_type operator+(const gcc_decimal32 rhs) { return rhs.underlying(); } friend return_type operator-(const gcc_decimal32 rhs) { return -rhs.underlying(); } + // 3.2.8 Binary arithmetic operators. + template + friend return_type operator+(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs.underlying() + rhs; } + + template + friend return_type operator+(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs + rhs.underlying(); } + + template + friend return_type operator-(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs.underlying() - rhs; } + + template + friend return_type operator-(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs - rhs.underlying(); } + + template + friend return_type operator*(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs.underlying() * rhs; } + + template + friend return_type operator*(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs * rhs.underlying(); } + + template + friend return_type operator/(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs.underlying() / rhs; } + + template + friend return_type operator/(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) + { return lhs / rhs.underlying(); } }; namespace detail { From 7edfe987303dc7383e7b41f3cd025002490b8805 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 17:25:16 -0500 Subject: [PATCH 08/55] Add static assert --- include/boost/decimal/gcc_decimal32.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index ef8944e8..d7c5339a 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -34,6 +34,8 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final private: + static_assert(sizeof(std::decimal::decimal32) == sizeof(std::uint32_t), "Incorrect size detected. std::decimal::decimal32 must be exactly 32 bits"); + std::decimal::decimal32 internal_decimal_ {}; // Returns the un-biased (quantum) exponent From c7ba62d135f3dfd4fd758219f58b5232005c729c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 17:39:25 -0500 Subject: [PATCH 09/55] Fix formatting and add 0 case --- include/boost/decimal/gcc_decimal32.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index d7c5339a..d63e3d9b 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -130,14 +130,17 @@ BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_unbiased_exponent(std::uint32 { case detail::d32_comb_11_mask: // bits 2 and 3 are the exp part of the combination field - expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); - break; + expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); + break; case detail::d32_comb_10_mask: expval = UINT32_C(0b10000000); - break; + break; case detail::d32_comb_01_mask: expval = UINT32_C(0b01000000); - break; + break; + case 0U: + expval = UINT32_C(0b00000000); + break; // LCOV_EXCL_START default: BOOST_DECIMAL_UNREACHABLE; From 672442a8118d08d6f50daa8bebf259bd43e66d78 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 23 Jan 2025 19:20:18 -0500 Subject: [PATCH 10/55] Use auto with concept / trailing return --- include/boost/decimal/gcc_decimal32.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index d63e3d9b..cc0157f1 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -79,42 +79,42 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final // 3.2.8 Binary arithmetic operators. template - friend return_type operator+(gcc_decimal32 lhs, Integral rhs) + friend auto operator+(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs.underlying() + rhs; } template - friend return_type operator+(Integral lhs, gcc_decimal32 rhs) + friend auto operator+(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs + rhs.underlying(); } template - friend return_type operator-(gcc_decimal32 lhs, Integral rhs) + friend auto operator-(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs.underlying() - rhs; } template - friend return_type operator-(Integral lhs, gcc_decimal32 rhs) + friend auto operator-(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs - rhs.underlying(); } template - friend return_type operator*(gcc_decimal32 lhs, Integral rhs) + friend auto operator*(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs.underlying() * rhs; } template - friend return_type operator*(Integral lhs, gcc_decimal32 rhs) + friend auto operator*(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs * rhs.underlying(); } template - friend return_type operator/(gcc_decimal32 lhs, Integral rhs) + friend auto operator/(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs.underlying() / rhs; } template - friend return_type operator/(Integral lhs, gcc_decimal32 rhs) + friend auto operator/(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs / rhs.underlying(); } }; From bb8c85e56294cc1d7eea3ce84a3749306d2441ec Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 09:03:22 -0500 Subject: [PATCH 11/55] Remove no discard as it breaks old compilers --- include/boost/decimal/detail/config.hpp | 4 ---- include/boost/decimal/gcc_decimal32.hpp | 12 ++++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 7cb5ba9c..5cbbbf1a 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -347,10 +347,6 @@ typedef unsigned __int128 uint128_t; # endif #endif -#ifndef BOOST_DECIMAL_NO_DISCARD -# define BOOST_DECIMAL_NO_DISCARD -#endif - #endif // Since we should not be able to pull these in from the STL in module mode define them ourselves diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index cc0157f1..93ba7e33 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -39,21 +39,21 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final std::decimal::decimal32 internal_decimal_ {}; // Returns the un-biased (quantum) exponent - BOOST_DECIMAL_NO_DISCARD inline auto unbiased_exponent() const noexcept -> exponent_type; + inline auto unbiased_exponent() const noexcept -> exponent_type; // Returns the biased exponent - BOOST_DECIMAL_NO_DISCARD inline auto biased_exponent() const noexcept -> biased_exponent_type; + inline auto biased_exponent() const noexcept -> biased_exponent_type; // Returns the significand complete with the bits implied from the combination field - BOOST_DECIMAL_NO_DISCARD inline auto full_significand() const noexcept -> significand_type; + inline auto full_significand() const noexcept -> significand_type; - BOOST_DECIMAL_NO_DISCARD inline auto isneg() const noexcept -> bool; + inline auto isneg() const noexcept -> bool; // Since we have the overhead of memcpy in order to decode anything // get them all at once if we are going to need it - BOOST_DECIMAL_NO_DISCARD inline auto to_components() const noexcept -> detail::decimal32_components; + inline auto to_components() const noexcept -> detail::decimal32_components; - BOOST_DECIMAL_NO_DISCARD inline auto underlying() const noexcept -> std::decimal::decimal32 { return internal_decimal_; } + inline auto underlying() const noexcept -> std::decimal::decimal32 { return internal_decimal_; } public: From 6f3535a069cd2ef40bc5a7b488b5b9890f62999f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 09:03:36 -0500 Subject: [PATCH 12/55] Add comparison operators --- include/boost/decimal/gcc_decimal32.hpp | 61 +++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 93ba7e33..85beb891 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -117,6 +117,67 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final friend auto operator/(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs / rhs.underlying(); } + + // 3.2.9 Comparison operators. + template + friend auto operator==(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs.underlying() + rhs; } + + template + friend auto operator==(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs + rhs.underlying(); } + + template + friend auto operator!=(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs.underlying() + rhs; } + + template + friend auto operator!=(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs + rhs.underlying(); } + + template + friend auto operator<(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs.underlying() + rhs; } + + template + friend auto operator<(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs + rhs.underlying(); } + + template + friend auto operator<=(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs.underlying() + rhs; } + + template + friend auto operator<=(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs + rhs.underlying(); } + + template + friend auto operator>(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs.underlying() + rhs; } + + template + friend auto operator>(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs + rhs.underlying(); } + + template + friend auto operator>=(gcc_decimal32 lhs, Integral rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs.underlying() + rhs; } + + template + friend auto operator>=(Integral lhs, gcc_decimal32 rhs) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) + { return lhs + rhs.underlying(); } }; namespace detail { From 395a16ae3a5f7d9a55802475d21502c2882a6b60 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 09:07:26 -0500 Subject: [PATCH 13/55] Add same type operators --- include/boost/decimal/gcc_decimal32.hpp | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 85beb891..077b790c 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -78,6 +78,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final friend return_type operator-(const gcc_decimal32 rhs) { return -rhs.underlying(); } // 3.2.8 Binary arithmetic operators. + friend auto operator+(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + {return lhs.underlying() + rhs.underlying(); } + template friend auto operator+(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) @@ -88,6 +91,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs + rhs.underlying(); } + friend auto operator-(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + {return lhs.underlying() - rhs.underlying(); } + template friend auto operator-(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) @@ -98,6 +104,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs - rhs.underlying(); } + friend auto operator*(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + {return lhs.underlying() * rhs.underlying(); } + template friend auto operator*(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) @@ -108,6 +117,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) { return lhs * rhs.underlying(); } + friend auto operator/(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + {return lhs.underlying() / rhs.underlying(); } + template friend auto operator/(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) @@ -119,6 +131,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final { return lhs / rhs.underlying(); } // 3.2.9 Comparison operators. + friend auto operator==(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + {return lhs.underlying() == rhs.underlying(); } + template friend auto operator==(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) @@ -129,6 +144,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs + rhs.underlying(); } + friend auto operator!=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + { return lhs.underlying() != rhs.underlying(); } + template friend auto operator!=(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) @@ -139,6 +157,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs + rhs.underlying(); } + friend auto operator<(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + {return lhs.underlying() < rhs.underlying(); } + template friend auto operator<(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) @@ -149,6 +170,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs + rhs.underlying(); } + friend auto operator<=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + { return lhs.underlying() <= rhs.underlying(); } + template friend auto operator<=(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) @@ -159,6 +183,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs + rhs.underlying(); } + friend auto operator>(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + { return lhs.underlying() > rhs.underlying(); } + template friend auto operator>(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) @@ -169,6 +196,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs + rhs.underlying(); } + friend auto operator>=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + { return lhs.underlying() >= rhs.underlying(); } + template friend auto operator>=(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) From 380ae035736a9f4930b81f63e9a9dee2a0fe7a81 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 10:05:18 -0500 Subject: [PATCH 14/55] Add combined accessor --- include/boost/decimal/gcc_decimal32.hpp | 49 +++++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 077b790c..28dabbf6 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -212,7 +212,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final namespace detail { -BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_unbiased_exponent(std::uint32_t bits_) noexcept -> gcc_decimal32::exponent_type +inline auto decode_gccd32_unbiased_exponent(std::uint32_t bits_) noexcept -> gcc_decimal32::exponent_type { gcc_decimal32::exponent_type expval {}; const auto exp_comb_bits {(bits_ & detail::d32_comb_11_mask)}; @@ -243,12 +243,12 @@ BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_unbiased_exponent(std::uint32 return expval; } -BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_biased_exponent(std::uint32_t bits) -> gcc_decimal32::biased_exponent_type +inline auto decode_gccd32_biased_exponent(std::uint32_t bits) -> gcc_decimal32::biased_exponent_type { return static_cast(decode_gccd32_unbiased_exponent(bits)) - detail::bias_v; } -BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_significand(std::uint32_t bits_) -> gcc_decimal32::significand_type +inline auto decode_gccd32_significand(std::uint32_t bits_) -> gcc_decimal32::significand_type { gcc_decimal32::significand_type significand {}; @@ -271,7 +271,7 @@ BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_significand(std::uint32_t bit return significand; } -BOOST_DECIMAL_NO_DISCARD inline auto decode_gccd32_sign(std::uint32_t bits_) -> bool +inline auto decode_gccd32_sign(std::uint32_t bits_) -> bool { return static_cast(bits_ & detail::d32_sign_mask); } @@ -312,9 +312,44 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c std::uint32_t bits_ {}; std::memcpy(&bits_, &internal_decimal_, sizeof(std::uint32_t)); - components.sig = detail::decode_gccd32_significand(bits_); - components.exp = detail::decode_gccd32_biased_exponent(bits_); - components.sign = detail::decode_gccd32_sign(bits_); + gcc_decimal32::exponent_type expval {}; + gcc_decimal32::significand_type significand {}; + const auto exp_comb_bits {(bits_ & detail::d32_comb_11_mask)}; + + switch (exp_comb_bits) + { + case detail::d32_comb_11_mask: + // bits 2 and 3 are the exp part of the combination field + expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); + significand = (bits_ & detail::d32_comb_11_significand_bits) == detail::d32_comb_11_significand_bits ? + UINT32_C(0b1001'0000000000'0000000000) : + UINT32_C(0b1000'0000000000'0000000000); + break; + case detail::d32_comb_10_mask: + expval = UINT32_C(0b10000000); + // Last three bits in the combination field, so we need to shift past the exp field + // which is next + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + break; + case detail::d32_comb_01_mask: + expval = UINT32_C(0b01000000); + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + break; + case 0U: + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_UNREACHABLE; + // LCOV_EXCL_STOP + } + + expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; + significand |= (bits_ & detail::d32_significand_mask); + + components.sig = significand; + components.exp = expval; + components.sign = bits_ & detail::d32_sign_mask; return components; } From ac7fb9adfee43ab98f0487e5ab24aad59d050d4b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 10:05:32 -0500 Subject: [PATCH 15/55] Allow accessors to be public for debugging --- include/boost/decimal/gcc_decimal32.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 28dabbf6..2d9d0bc8 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -38,6 +38,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final std::decimal::decimal32 internal_decimal_ {}; +#ifdef BOOST_DECIMAL_DEBUG_ACCESSORS +public: +#endif // Returns the un-biased (quantum) exponent inline auto unbiased_exponent() const noexcept -> exponent_type; From 4ac7f63783ed318d92f98e9a5b0b3eae442759a0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:14:08 -0500 Subject: [PATCH 16/55] Allow accessor access --- include/boost/decimal/decimal32.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index a10ff117..f4347c26 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -143,6 +143,9 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m std::uint32_t bits_ {}; +#ifdef BOOST_DECIMAL_DEBUG_ACCESSORS +public: +#endif // Returns the un-biased (quantum) exponent constexpr auto unbiased_exponent() const noexcept -> exponent_type ; @@ -153,6 +156,9 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m constexpr auto full_significand() const noexcept -> significand_type ; constexpr auto isneg() const noexcept -> bool; +#ifdef BOOST_DECIMAL_DEBUG_ACCESSORS +private: +#endif // Attempts conversion to integral type: // If this is nan sets errno to EINVAL and returns 0 // If this is not representable sets errno to ERANGE and returns 0 From ccf818d711eeea8f69d6e2651d5543d0d3447673 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:17:34 -0500 Subject: [PATCH 17/55] Add test of encoding / decoding vs decimal32 --- test/Jamfile | 3 ++ test/test_basic_gcc_decimal32.cpp | 82 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 test/test_basic_gcc_decimal32.cpp diff --git a/test/Jamfile b/test/Jamfile index 690206c7..8e12d8da 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -191,3 +191,6 @@ compile compile_tests/numbers_compile.cpp ; compile compile_tests/string_compile.cpp ; compile compile_tests/uint128.cpp ; compile compile_tests/gcc_decimal32.cpp ; + +# Wrapper types +run test_basic_gcc_decimal32.cpp ; diff --git a/test/test_basic_gcc_decimal32.cpp b/test/test_basic_gcc_decimal32.cpp new file mode 100644 index 00000000..dcb47d8e --- /dev/null +++ b/test/test_basic_gcc_decimal32.cpp @@ -0,0 +1,82 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#define BOOST_DECIMAL_DEBUG_ACCESSORS + +#include +#include +#include +#include +#include +#include +#include +#include + +void compare_bits(long long coeff, int exp) +{ + const boost::decimal::decimal32 dec32_val {coeff, exp}; + const boost::decimal::gcc_decimal32 gcc_val {coeff, exp}; + + if (!BOOST_TEST_EQ(dec32_val.full_significand(), gcc_val.full_significand()) || + !BOOST_TEST_EQ(dec32_val.biased_exponent(), gcc_val.biased_exponent()) || + !BOOST_TEST_EQ(dec32_val.unbiased_exponent(), gcc_val.unbiased_exponent()) || + !BOOST_TEST_EQ(dec32_val.isneg(), gcc_val.isneg())) + { + std::uint32_t boost_bits; + std::memcpy(&boost_bits, &dec32_val, sizeof(std::uint32_t)); + + std::uint32_t gcc_bits; + std::memcpy(&gcc_bits, &gcc_val, sizeof(std::uint32_t)); + + std::cerr << "Coeff: " << coeff << '\n' + << " Exp: " << exp << '\n' + << "Boost: " << std::bitset<32>(boost_bits) << "\n" + << " GCC: " << std::bitset<32>(gcc_bits) << "\n" << std::endl; + } +} + +int main() +{ + // 2^0 + compare_bits(1, 0); + + // 2^1 + compare_bits(2, 0); + + // 2^21 + compare_bits(2097152, 0); + + // 2^22 + compare_bits(4194304, 0); + + // 2^23 + compare_bits(8388608, 0); + + // 2^24 + // Exceeds digits10 so needs to be rounded + compare_bits(16777216, 0); + + // Random significands with 0 exponent + std::mt19937_64 rng{42}; + std::uniform_int_distribution sig_dist(-10000000, 1000000); + for (int i {}; i < 1024; ++i) + { + compare_bits(sig_dist(rng), 0); + } + + // Random powers of 2 + std::uniform_int_distribution exp_dist(-88, 89); + for (int i {}; i < 1024; ++i) + { + compare_bits(2, exp_dist(rng)); + } + + // Put it all together now + for (int i {}; i < 1024; ++i) + { + compare_bits(sig_dist(rng), exp_dist(rng)); + } + + return boost::report_errors(); +} From fc6de5f01dac03e29192e6d1a6f15a123a0dc0b1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:18:08 -0500 Subject: [PATCH 18/55] Reverse engineer GCC/IBM type --- include/boost/decimal/gcc_decimal32.hpp | 117 +++++++++++------------- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 2d9d0bc8..5c83ee76 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -23,6 +23,33 @@ namespace boost { namespace decimal { +namespace detail { + +// Masks to update the significand based on the combination field +// GCC / IBM do not follow the IEEE 754 encoding standard for BID +// Reverse engineering found the following patters: +// +// Comb. Exponent Significand +// s eeeeeeee ttttttttttttttttttttttt - sign + 2 steering bits concatenate to 6 bits of exponent + 23 bits of significand like float +// s 11 eeeeeeee [t]ttttttttttttttttttttt - sign + 2 steering bits + 8 bits of exponent + 21 bits of significand +// +// Only is the type different in steering 11 which yields significand 100 + 21 bits giving us our 24 total bits of precision + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_sign_mask = UINT32_C(0b10000000000000000000000000000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_steering_bits_mask = UINT32_C(0b01100000000000000000000000000000); + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_00_steering_bits = UINT32_C(0); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_steering_bits = UINT32_C(0b00100000000000000000000000000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_10_steering_bits = UINT32_C(0b01000000000000000000000000000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_steering_bits = gccd32_steering_bits_mask; + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_exp_mask = UINT32_C(0b01111111100000000000000000000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_exp_mask = UINT32_C(0b00011111111000000000000000000000); + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_significand_mask = UINT32_C(0b00000000011111111111111111111111); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_significand_mask = UINT32_C(0b00000000000111111111111111111111); +} // namespace detail + // This type is a wrapper around gcc std::decimal::decimal32 to allow it to use // the standard library provided by Boost.Decimal BOOST_DECIMAL_EXPORT class gcc_decimal32 final @@ -64,6 +91,8 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final gcc_decimal32() = default; + explicit gcc_decimal32(std::decimal::decimal32 decimal) { internal_decimal_ = decimal; } + // 3.2.5 Initialization from coefficient and exponent. gcc_decimal32(long long coeff, int exp); gcc_decimal32(unsigned long long coeff, int exp); @@ -218,30 +247,17 @@ namespace detail { inline auto decode_gccd32_unbiased_exponent(std::uint32_t bits_) noexcept -> gcc_decimal32::exponent_type { gcc_decimal32::exponent_type expval {}; - const auto exp_comb_bits {(bits_ & detail::d32_comb_11_mask)}; + const auto steering_bits {(bits_ & gccd32_steering_bits_mask)}; - switch (exp_comb_bits) + // 3 of the 4 steering patterns leave this laid out like a binary float instead of an IEEE 754 decimal float + if (steering_bits == gccd32_11_steering_bits) { - case detail::d32_comb_11_mask: - // bits 2 and 3 are the exp part of the combination field - expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); - break; - case detail::d32_comb_10_mask: - expval = UINT32_C(0b10000000); - break; - case detail::d32_comb_01_mask: - expval = UINT32_C(0b01000000); - break; - case 0U: - expval = UINT32_C(0b00000000); - break; - // LCOV_EXCL_START - default: - BOOST_DECIMAL_UNREACHABLE; - // LCOV_EXCL_STOP + expval |= (bits_ & gccd32_11_exp_mask) >> 21U; + } + else + { + expval |= (bits_ & gccd32_01_exp_mask) >> 23U; } - - expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; return expval; } @@ -255,28 +271,24 @@ inline auto decode_gccd32_significand(std::uint32_t bits_) -> gcc_decimal32::sig { gcc_decimal32::significand_type significand {}; - if ((bits_ & detail::d32_comb_11_mask) == detail::d32_comb_11_mask) + const auto steering_bits {(bits_ & gccd32_steering_bits_mask)}; + + if (steering_bits == gccd32_11_steering_bits) { - // Only need the one bit of T because the other 3 are implied - significand = (bits_ & detail::d32_comb_11_significand_bits) == detail::d32_comb_11_significand_bits ? - UINT32_C(0b1001'0000000000'0000000000) : - UINT32_C(0b1000'0000000000'0000000000); + significand = UINT32_C(0b1000'0000000000'0000000000); + significand |= (bits_ & gccd32_11_significand_mask); } else { - // Last three bits in the combination field, so we need to shift past the exp field - // which is next - significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + significand |= (bits_ & gccd32_01_significand_mask); } - significand |= (bits_ & detail::d32_significand_mask); - return significand; } inline auto decode_gccd32_sign(std::uint32_t bits_) -> bool { - return static_cast(bits_ & detail::d32_sign_mask); + return static_cast(bits_ & gccd32_sign_mask); } } // detail @@ -317,42 +329,23 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c gcc_decimal32::exponent_type expval {}; gcc_decimal32::significand_type significand {}; - const auto exp_comb_bits {(bits_ & detail::d32_comb_11_mask)}; + const auto steering_bits {(bits_ & detail::gccd32_steering_bits_mask)}; - switch (exp_comb_bits) + if (steering_bits == detail::gccd32_11_steering_bits) { - case detail::d32_comb_11_mask: - // bits 2 and 3 are the exp part of the combination field - expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); - significand = (bits_ & detail::d32_comb_11_significand_bits) == detail::d32_comb_11_significand_bits ? - UINT32_C(0b1001'0000000000'0000000000) : - UINT32_C(0b1000'0000000000'0000000000); - break; - case detail::d32_comb_10_mask: - expval = UINT32_C(0b10000000); - // Last three bits in the combination field, so we need to shift past the exp field - // which is next - significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; - break; - case detail::d32_comb_01_mask: - expval = UINT32_C(0b01000000); - significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; - break; - case 0U: - significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; - break; - // LCOV_EXCL_START - default: - BOOST_DECIMAL_UNREACHABLE; - // LCOV_EXCL_STOP + significand = UINT32_C(0b1000'0000000000'0000000000); + significand |= (bits_ & detail::gccd32_11_significand_mask); + expval |= (bits_ & detail::gccd32_11_exp_mask) >> 21U; + } + else + { + significand |= (bits_ & detail::gccd32_01_significand_mask); + expval |= (bits_ & detail::gccd32_01_exp_mask) >> 23U; } - - expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; - significand |= (bits_ & detail::d32_significand_mask); components.sig = significand; components.exp = expval; - components.sign = bits_ & detail::d32_sign_mask; + components.sign = bits_ & detail::gccd32_sign_mask; return components; } From a80494ad6b1ae37a88ed0aa99090f5869d233715 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:26:27 -0500 Subject: [PATCH 19/55] Add 1 shot decode function for decimal32 --- include/boost/decimal/decimal32.hpp | 54 ++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index f4347c26..04e9c670 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -156,6 +156,9 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m constexpr auto full_significand() const noexcept -> significand_type ; constexpr auto isneg() const noexcept -> bool; + // Returns a complete struct so we don't have to decode multiple times + constexpr auto to_components() const noexcept -> detail::decimal32_components; + #ifdef BOOST_DECIMAL_DEBUG_ACCESSORS private: #endif @@ -1446,6 +1449,52 @@ constexpr auto decimal32::full_significand() const noexcept -> significand_type return significand; } +constexpr auto decimal32::isneg() const noexcept -> bool +{ + return static_cast(bits_ & detail::d32_sign_mask); +} + +constexpr auto decimal32::to_components() const noexcept -> detail::decimal32_components +{ + detail::decimal32_components components {}; + + exponent_type expval {}; + significand_type significand {}; + + const auto comb_bits {(bits_ & detail::d32_comb_11_mask)}; + + switch (comb_bits) + { + case detail::d32_comb_11_mask: + // bits 2 and 3 are the exp part of the combination field + expval = (bits_ & detail::d32_comb_11_exp_bits) >> (detail::d32_significand_bits + 1); + // Only need the one bit of T because the other 3 are implied + significand = (bits_ & detail::d32_comb_11_significand_bits) == detail::d32_comb_11_significand_bits ? + UINT32_C(0b1001'0000000000'0000000000) : + UINT32_C(0b1000'0000000000'0000000000); + break; + case detail::d32_comb_10_mask: + expval = UINT32_C(0b10000000); + // Last three bits in the combination field, so we need to shift past the exp field + // which is next + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + break; + case detail::d32_comb_01_mask: + expval = UINT32_C(0b01000000); + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + break; + } + + significand |= (bits_ & detail::d32_significand_mask); + expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; + + components.sig = significand; + components.exp = expval; + components.sign = bits_ & detail::d32_sign_mask; + + return components; +} + template constexpr auto decimal32::edit_significand(T sig) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, T, void) @@ -1453,11 +1502,6 @@ constexpr auto decimal32::edit_significand(T sig) noexcept *this = decimal32(sig, this->biased_exponent(), this->isneg()); } -constexpr auto decimal32::isneg() const noexcept -> bool -{ - return static_cast(bits_ & detail::d32_sign_mask); -} - // Allows changing the sign even on nans and infs constexpr auto decimal32::edit_sign(bool sign) noexcept -> void { From e777f8dcfba18e58f0f2bbeaf0b987bcedb804dc Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:41:36 -0500 Subject: [PATCH 20/55] Fix bias --- include/boost/decimal/decimal32.hpp | 5 ++++- include/boost/decimal/gcc_decimal32.hpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 04e9c670..f9224a0b 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -1483,13 +1483,16 @@ constexpr auto decimal32::to_components() const noexcept -> detail::decimal32_co expval = UINT32_C(0b01000000); significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; break; + case 0U: + significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits; + break; } significand |= (bits_ & detail::d32_significand_mask); expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; components.sig = significand; - components.exp = expval; + components.exp = expval - detail::bias_v; components.sign = bits_ & detail::d32_sign_mask; return components; diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 5c83ee76..470cb945 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -344,7 +344,7 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c } components.sig = significand; - components.exp = expval; + components.exp = expval - detail::bias_v; components.sign = bits_ & detail::gccd32_sign_mask; return components; From 91b90ccf5c5cc574bc2148e7b8c47090cdc06b55 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:41:47 -0500 Subject: [PATCH 21/55] Add testing of 1 shot decoding --- test/test_basic_gcc_decimal32.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test_basic_gcc_decimal32.cpp b/test/test_basic_gcc_decimal32.cpp index dcb47d8e..9217acf9 100644 --- a/test/test_basic_gcc_decimal32.cpp +++ b/test/test_basic_gcc_decimal32.cpp @@ -34,6 +34,18 @@ void compare_bits(long long coeff, int exp) << "Boost: " << std::bitset<32>(boost_bits) << "\n" << " GCC: " << std::bitset<32>(gcc_bits) << "\n" << std::endl; } + + // Separate test of the to_components + const auto dec_struct = dec32_val.to_components(); + const auto gcc_struct = gcc_val.to_components(); + + BOOST_TEST_EQ(gcc_struct.sign, gcc_val.isneg()); + BOOST_TEST_EQ(gcc_struct.sig, gcc_val.full_significand()); + BOOST_TEST_EQ(gcc_struct.exp, gcc_val.biased_exponent()); + + BOOST_TEST_EQ(dec_struct.sign, gcc_struct.sign); + BOOST_TEST_EQ(dec_struct.sig, gcc_struct.sig); + BOOST_TEST_EQ(dec_struct.exp, gcc_struct.exp); } int main() From 566389adba5e36dfac57e2a99fe7e18a1e015a08 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 16:52:57 -0500 Subject: [PATCH 22/55] Put hot branch first --- include/boost/decimal/gcc_decimal32.hpp | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 470cb945..c7c17dba 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -250,13 +250,13 @@ inline auto decode_gccd32_unbiased_exponent(std::uint32_t bits_) noexcept -> gcc const auto steering_bits {(bits_ & gccd32_steering_bits_mask)}; // 3 of the 4 steering patterns leave this laid out like a binary float instead of an IEEE 754 decimal float - if (steering_bits == gccd32_11_steering_bits) + if (steering_bits != gccd32_11_steering_bits) { - expval |= (bits_ & gccd32_11_exp_mask) >> 21U; + expval |= (bits_ & gccd32_01_exp_mask) >> 23U; } else { - expval |= (bits_ & gccd32_01_exp_mask) >> 23U; + expval |= (bits_ & gccd32_11_exp_mask) >> 21U; } return expval; @@ -273,14 +273,14 @@ inline auto decode_gccd32_significand(std::uint32_t bits_) -> gcc_decimal32::sig const auto steering_bits {(bits_ & gccd32_steering_bits_mask)}; - if (steering_bits == gccd32_11_steering_bits) + if (steering_bits != gccd32_11_steering_bits) { - significand = UINT32_C(0b1000'0000000000'0000000000); - significand |= (bits_ & gccd32_11_significand_mask); + significand |= (bits_ & gccd32_01_significand_mask); } else { - significand |= (bits_ & gccd32_01_significand_mask); + significand = UINT32_C(0b1000'0000000000'0000000000); + significand |= (bits_ & gccd32_11_significand_mask); } return significand; @@ -331,16 +331,16 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c gcc_decimal32::significand_type significand {}; const auto steering_bits {(bits_ & detail::gccd32_steering_bits_mask)}; - if (steering_bits == detail::gccd32_11_steering_bits) + if (steering_bits != detail::gccd32_11_steering_bits) { - significand = UINT32_C(0b1000'0000000000'0000000000); - significand |= (bits_ & detail::gccd32_11_significand_mask); - expval |= (bits_ & detail::gccd32_11_exp_mask) >> 21U; + significand |= (bits_ & detail::gccd32_01_significand_mask); + expval |= (bits_ & detail::gccd32_01_exp_mask) >> 23U; } else { - significand |= (bits_ & detail::gccd32_01_significand_mask); - expval |= (bits_ & detail::gccd32_01_exp_mask) >> 23U; + significand = UINT32_C(0b1000'0000000000'0000000000); + significand |= (bits_ & detail::gccd32_11_significand_mask); + expval |= (bits_ & detail::gccd32_11_exp_mask) >> 21U; } components.sig = significand; From f5f060a049a3bd06eb379b64179911b3f4a71580 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jan 2025 17:19:32 -0500 Subject: [PATCH 23/55] Fix sign conversion --- include/boost/decimal/decimal32.hpp | 2 +- include/boost/decimal/gcc_decimal32.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index f9224a0b..3179dc91 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -1492,7 +1492,7 @@ constexpr auto decimal32::to_components() const noexcept -> detail::decimal32_co expval |= (bits_ & detail::d32_exponent_mask) >> detail::d32_significand_bits; components.sig = significand; - components.exp = expval - detail::bias_v; + components.exp = static_cast(expval) - detail::bias_v; components.sign = bits_ & detail::d32_sign_mask; return components; diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index c7c17dba..db2ae29a 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -344,7 +344,7 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c } components.sig = significand; - components.exp = expval - detail::bias_v; + components.exp = static_cast(expval) - detail::bias_v; components.sign = bits_ & detail::gccd32_sign_mask; return components; From 0aa727d47254cd7535e3bbfba06825715d17a9aa Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 27 Jan 2025 11:37:25 -0500 Subject: [PATCH 24/55] Change header guards for non-GCC platforms --- include/boost/decimal/gcc_decimal32.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index db2ae29a..316f546f 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -5,7 +5,7 @@ #ifndef BOOST_DECIMAL_GCC_DECIMAL32_HPP #define BOOST_DECIMAL_GCC_DECIMAL32_HPP -#if __has_include() +#if __has_include() && defined(__GNUC__) && __GNUC__ >= 7 #include #include From d4b0d30c07296d4946c23b406186701fe289a932 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 27 Jan 2025 13:51:35 -0500 Subject: [PATCH 25/55] Separate constructors to reduce ambiguity --- include/boost/decimal/gcc_decimal32.hpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 316f546f..8b441df5 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -94,8 +94,29 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final explicit gcc_decimal32(std::decimal::decimal32 decimal) { internal_decimal_ = decimal; } // 3.2.5 Initialization from coefficient and exponent. - gcc_decimal32(long long coeff, int exp); - gcc_decimal32(unsigned long long coeff, int exp); + template && detail::is_signed_v, bool> = true> + gcc_decimal32(Integer coeff) + { + internal_decimal_ = std::decimal::make_decimal32(static_cast(coeff), 0); + } + + template && detail::is_unsigned_v, bool> = true> + gcc_decimal32(Integer coeff) + { + internal_decimal_ = std::decimal::make_decimal32(static_cast(coeff), 0); + } + + template && detail::is_signed_v, bool> = true> + gcc_decimal32(Integer coeff, int exp) + { + internal_decimal_ = std::decimal::make_decimal32(static_cast(coeff), exp); + } + + template && detail::is_unsigned_v, bool> = true> + gcc_decimal32(Integer coeff, int exp) + { + internal_decimal_ = std::decimal::make_decimal32(static_cast(coeff), exp); + } // Non-conforming extension: Conversion to integral type. inline operator long long() const noexcept; From ccc5ca9350980049cf6d985b4323a4f0ec3011ff Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 27 Jan 2025 14:03:07 -0500 Subject: [PATCH 26/55] Fix operators and add basic IO stream --- include/boost/decimal/gcc_decimal32.hpp | 76 ++++++++++++++++++------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 8b441df5..50fd95b7 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -190,12 +190,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template friend auto operator==(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs.underlying() + rhs; } + { return lhs.underlying() == rhs; } template friend auto operator==(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs + rhs.underlying(); } + { return lhs == rhs.underlying(); } friend auto operator!=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type { return lhs.underlying() != rhs.underlying(); } @@ -203,12 +203,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template friend auto operator!=(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs.underlying() + rhs; } + { return lhs.underlying() != rhs; } template friend auto operator!=(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs + rhs.underlying(); } + { return lhs != rhs.underlying(); } friend auto operator<(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type {return lhs.underlying() < rhs.underlying(); } @@ -216,12 +216,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template friend auto operator<(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs.underlying() + rhs; } + { return lhs.underlying() < rhs; } template friend auto operator<(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs + rhs.underlying(); } + { return lhs < rhs.underlying(); } friend auto operator<=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type { return lhs.underlying() <= rhs.underlying(); } @@ -229,12 +229,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template friend auto operator<=(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs.underlying() + rhs; } + { return lhs.underlying() <= rhs; } template friend auto operator<=(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs + rhs.underlying(); } + { return lhs <= rhs.underlying(); } friend auto operator>(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type { return lhs.underlying() > rhs.underlying(); } @@ -242,12 +242,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template friend auto operator>(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs.underlying() + rhs; } + { return lhs.underlying() > rhs; } template friend auto operator>(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs + rhs.underlying(); } + { return lhs > rhs.underlying(); } friend auto operator>=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type { return lhs.underlying() >= rhs.underlying(); } @@ -255,14 +255,49 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template friend auto operator>=(gcc_decimal32 lhs, Integral rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs.underlying() + rhs; } + { return lhs.underlying() >= rhs; } template friend auto operator>=(Integral lhs, gcc_decimal32 rhs) BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) - { return lhs + rhs.underlying(); } + { return lhs >= rhs.underlying(); } + + // A basic output operator for now + template + friend auto operator<<(std::basic_ostream& os, const gcc_decimal32& d) -> std::basic_ostream& + { + if (d.isneg()) + { + os << "-"; + } + else + { + os << "+"; + } + + os << d.full_significand(); + + const auto exp {d.biased_exponent()}; + + if (exp < 0) + { + os << "e-" << exp; + } + else + { + os << "e+" << exp; + } + + return os; + } }; +template +auto operator<<(std::basic_ostream& os, const std::decimal::decimal32& d) -> std::basic_ostream& +{ + return os << gcc_decimal32{d}; +} + namespace detail { inline auto decode_gccd32_unbiased_exponent(std::uint32_t bits_) noexcept -> gcc_decimal32::exponent_type @@ -371,16 +406,6 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c return components; } -inline gcc_decimal32::gcc_decimal32(long long coeff, int exp) -{ - internal_decimal_ = std::decimal::make_decimal32(coeff, exp); -} - -inline gcc_decimal32::gcc_decimal32(unsigned long long coeff, int exp) -{ - internal_decimal_ = std::decimal::make_decimal32(coeff, exp); -} - inline gcc_decimal32::operator long long() const noexcept { return std::decimal::decimal32_to_long_long(internal_decimal_); @@ -401,6 +426,13 @@ inline gcc_decimal32::operator long double() const noexcept return std::decimal::decimal32_to_long_double(internal_decimal_); } +namespace detail { + +template <> +struct is_decimal_floating_point { static constexpr bool value = true; }; + +}// namespace detial + } // namespace decimal } // namespace boost From 5aad92d01b66ea7e3d9073dfa7310d4e36d5a30d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 27 Jan 2025 14:03:38 -0500 Subject: [PATCH 27/55] Add tests --- test/Jamfile | 1 + test/random_gccdecimal32_comp.cpp | 632 ++++++++++++++++++++++++++++++ 2 files changed, 633 insertions(+) create mode 100644 test/random_gccdecimal32_comp.cpp diff --git a/test/Jamfile b/test/Jamfile index 8e12d8da..de252a49 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -194,3 +194,4 @@ compile compile_tests/gcc_decimal32.cpp ; # Wrapper types run test_basic_gcc_decimal32.cpp ; +run random_gccdecimal32_comp.cpp ; diff --git a/test/random_gccdecimal32_comp.cpp b/test/random_gccdecimal32_comp.cpp new file mode 100644 index 00000000..191752c7 --- /dev/null +++ b/test/random_gccdecimal32_comp.cpp @@ -0,0 +1,632 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include "../include/boost/decimal/gcc_decimal32.hpp" + +#ifdef BOOST_DECIMAL_HAS_GCC_DECIMAL32 + +#include +#include +#include + +using namespace boost::decimal; + +#if !defined(BOOST_DECIMAL_REDUCE_TEST_DEPTH) +static constexpr auto N = static_cast(1024U); // Number of trials +#else +static constexpr auto N = static_cast(1024U >> 4U); // Number of trials +#endif + +// NOLINTNEXTLINE : Seed with a constant for repeatability +static std::mt19937_64 rng(42); // NOSONAR : Global rng is not const + +template +void random_LT(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST((dec1 < dec2) == (val1 < val2))) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nVal 2: " << val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + // Edge cases + //BOOST_TEST(gcc_decimal32(dist(rng)) < std::numeric_limits::infinity()); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) < -std::numeric_limits::infinity())); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) < std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(std::numeric_limits::quiet_NaN() < std::numeric_limits::quiet_NaN())); +} + +template +void random_mixed_LT(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST((dec1 < dec2) == (val1 < val2))) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + // Reverse order of the operands + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const T dec1 {static_cast(gcc_decimal32(val1))}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST((dec1 < dec2) == (val1 < val2))) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + // Edge Cases + //BOOST_TEST_EQ(gcc_decimal32(1) < T(1), false); + //BOOST_TEST_EQ(gcc_decimal32(10) < T(10), false); + //BOOST_TEST_EQ(T(1) < gcc_decimal32(1), false); + //BOOST_TEST_EQ(T(10) < gcc_decimal32(10), false); + //BOOST_TEST_EQ(std::numeric_limits::infinity() < T(1), false); + //BOOST_TEST_EQ(-std::numeric_limits::infinity() < T(1), true); + //BOOST_TEST_EQ(std::numeric_limits::quiet_NaN() < T(1), false); +} + +/* +template +void random_LE(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST_EQ(dec1 <= dec2, val1 <= val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(gcc_decimal32(dist(rng)) <= std::numeric_limits::infinity()); + BOOST_TEST(!(gcc_decimal32(dist(rng)) <= -std::numeric_limits::infinity())); + BOOST_TEST(!(gcc_decimal32(dist(rng)) <= std::numeric_limits::quiet_NaN())); + BOOST_TEST(!(std::numeric_limits::quiet_NaN() <= std::numeric_limits::quiet_NaN())); +} + +template +void random_mixed_LE(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST_EQ(dec1 <= dec2, val1 <= val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(dist(rng) <= std::numeric_limits::infinity()); + BOOST_TEST(!(dist(rng) <= -std::numeric_limits::infinity())); + BOOST_TEST(!(dist(rng) <= std::numeric_limits::quiet_NaN())); +} + +template +void random_GT(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST_EQ(dec1 > dec2, val1 > val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(!(gcc_decimal32(dist(rng)) > std::numeric_limits::infinity())); + BOOST_TEST((gcc_decimal32(dist(rng)) > -std::numeric_limits::infinity())); + BOOST_TEST(!(gcc_decimal32(dist(rng)) > std::numeric_limits::quiet_NaN())); + BOOST_TEST(!(std::numeric_limits::quiet_NaN() > std::numeric_limits::quiet_NaN())); +} + +template +void random_mixed_GT(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST_EQ(dec1 > dec2, val1 > val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(!(dist(rng) > std::numeric_limits::infinity())); + BOOST_TEST((dist(rng) > -std::numeric_limits::infinity())); + BOOST_TEST(!(dist(rng) > std::numeric_limits::quiet_NaN())); +} + +template +void random_GE(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST_EQ(dec1 >= dec2, val1 >= val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(!(gcc_decimal32(dist(rng)) >= std::numeric_limits::infinity())); + BOOST_TEST((gcc_decimal32(dist(rng)) >= -std::numeric_limits::infinity())); + BOOST_TEST(!(gcc_decimal32(dist(rng)) >= std::numeric_limits::quiet_NaN())); + BOOST_TEST(!(std::numeric_limits::quiet_NaN() >= std::numeric_limits::quiet_NaN())); +} + +template +void random_mixed_GE(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST_EQ(dec1 >= dec2, val1 >= val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(!(dist(rng) >= std::numeric_limits::infinity())); + BOOST_TEST((dist(rng) >= -std::numeric_limits::infinity())); + BOOST_TEST(!(dist(rng) >= std::numeric_limits::quiet_NaN())); +} + +template +void spot_test_mixed_ge(T lhs, T rhs) +{ + const gcc_decimal32 val1 {lhs}; + const T val2 {static_cast(gcc_decimal32(rhs))}; + + if (!BOOST_TEST_EQ(val1 >= val2, lhs >= rhs)) + { + // LCOV_EXCL_START + std::cerr << " LHS: " << lhs + << "\nLHS D: " << val1 + << "\n RHS: " << rhs + << "\nRHS D: " << val2 << std::endl; + // LCOV_EXCL_STOP + } +} + +template +void random_EQ(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST_EQ(dec1 == dec2, val1 == val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST(!(std::numeric_limits::quiet_NaN() == std::numeric_limits::quiet_NaN())); +} + +template +void random_mixed_EQ(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST_EQ(dec1 == dec2, val1 == val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const T dec1 {static_cast(gcc_decimal32(val1))}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST_EQ(dec1 == dec2, val1 == val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + // Edge Cases + BOOST_TEST_EQ(gcc_decimal32(1), T(1)); + BOOST_TEST_EQ(gcc_decimal32(10), T(10)); + BOOST_TEST_EQ(gcc_decimal32(100), T(100)); + BOOST_TEST_EQ(gcc_decimal32(1000), T(1000)); + BOOST_TEST_EQ(gcc_decimal32(10000), T(10000)); + BOOST_TEST_EQ(gcc_decimal32(100000), T(100000)); + BOOST_TEST_EQ(std::numeric_limits::quiet_NaN() == T(1), false); + BOOST_TEST_EQ(std::numeric_limits::infinity() == T(1), false); +} + +template +void random_NE(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST_EQ(dec1 != dec2, val1 != val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST((std::numeric_limits::quiet_NaN() != std::numeric_limits::quiet_NaN())); +} + +template +void random_mixed_NE(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST_EQ(dec1 != dec2, val1 != val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } +} + +#ifdef BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR +template +void random_SPACESHIP(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + if (!BOOST_TEST((dec1 <=> dec2) == (val1 <=> val2))) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + BOOST_TEST((gcc_decimal32(dist(rng)) <=> std::numeric_limits::quiet_NaN()) == std::partial_ordering::unordered); + BOOST_TEST((std::numeric_limits::quiet_NaN() <=> std::numeric_limits::quiet_NaN()) == std::partial_ordering::unordered); +} + +template +void random_mixed_SPACESHIP(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + if (!BOOST_TEST((dec1 <=> dec2) == (val1 <=> val2))) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 << std::endl; + // LCOV_EXCL_STOP + } + } + + if (!BOOST_TEST((dist(rng) <=> std::numeric_limits::quiet_NaN()) == std::partial_ordering::unordered)) + { + // LCOV_EXCL_START + const auto eval {dist(rng) <=> std::numeric_limits::quiet_NaN()}; + if (eval == std::partial_ordering::less) + std::cerr << "Less" << std::endl; + else if (eval == std::partial_ordering::greater) + std::cerr << "Greater" << std::endl; + else if (eval == std::partial_ordering::equivalent) + std::cerr << "Equivalent" << std::endl; + else + std::cerr << "Unordered" << std::endl; + // LCOV_EXCL_STOP + } + + BOOST_TEST((std::numeric_limits::quiet_NaN() <=> std::numeric_limits::quiet_NaN()) == std::partial_ordering::unordered); +} +#endif + +*/ + +int main() +{ + random_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_LT(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); + + /* + random_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_LE(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_LE(std::numeric_limits::min(), std::numeric_limits::max()); + + random_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_GT(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GT(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GT(std::numeric_limits::min(), std::numeric_limits::max()); + + random_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_GE(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_GE(std::numeric_limits::min(), std::numeric_limits::max()); + + spot_test_mixed_ge(UINT64_C(15984034765439402622), UINT64_C(1366685175759710132)); + + random_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_EQ(std::numeric_limits::min(), std::numeric_limits::max()); + + random_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_NE(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_NE(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_NE(std::numeric_limits::min(), std::numeric_limits::max()); + + #ifdef BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR + random_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + + random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); + #endif + + constexpr auto pos_zero = boost::decimal::gcc_decimal32{0, 0, false}; + constexpr auto neg_zero = boost::decimal::gcc_decimal32{0, 0, true}; + BOOST_TEST_EQ(pos_zero, neg_zero); + */ + + return boost::report_errors(); +} + +#else + +#include + +int main() +{ + std::cerr << "Tests not run" << std::endl; + return 1; +} + +#endif From 854a37e2cc1f6d61c58dc06da1b0bbad96a91125 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:01:21 -0500 Subject: [PATCH 28/55] Add cmath function framework --- include/boost/decimal/gcc_decimal32.hpp | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 50fd95b7..d343becc 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -85,6 +85,14 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final inline auto underlying() const noexcept -> std::decimal::decimal32 { return internal_decimal_; } + // cmath functions that are easier as friends + friend inline auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + friend inline auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + friend inline auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + friend inline auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + friend inline auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + friend inline auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + public: using return_type = std::decimal::decimal32; @@ -406,6 +414,40 @@ inline auto gcc_decimal32::to_components() const noexcept -> detail::decimal32_c return components; } +inline auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool +{ + return rhs.isneg(); +} + +inline auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool +{ + static_cast(rhs); + return false; +} + +inline auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool +{ + static_cast(rhs); + return false; +} + +inline auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool +{ + static_cast(rhs); + return true; +} + +inline auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool +{ + static_cast(rhs); + return true; +} + +inline gcc_decimal32::operator unsigned long long() const noexcept +{ + return to_integral(*this); +} + inline gcc_decimal32::operator long long() const noexcept { return std::decimal::decimal32_to_long_long(internal_decimal_); From 2f8dffbe793f76982094da34d7701ce6eb58ac3b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:01:45 -0500 Subject: [PATCH 29/55] Move check for libstdc++ decimal --- include/boost/decimal/detail/config.hpp | 4 ++++ include/boost/decimal/gcc_decimal32.hpp | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 5cbbbf1a..c58d86de 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -360,4 +360,8 @@ typedef unsigned __int128 uint128_t; # endif #endif +#if __has_include() && defined(__GNUC__) && __GNUC__ >= 7 +# define BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL +#endif + #endif // BOOST_DECIMAL_DETAIL_CONFIG_HPP diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index d343becc..47006be1 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -5,11 +5,13 @@ #ifndef BOOST_DECIMAL_GCC_DECIMAL32_HPP #define BOOST_DECIMAL_GCC_DECIMAL32_HPP -#if __has_include() && defined(__GNUC__) && __GNUC__ >= 7 +#include + +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL #include #include -#include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE From cee24fb1d5ae093315d31834b581f0648fbea595 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:02:05 -0500 Subject: [PATCH 30/55] Add wrapper overload to internal type traits --- include/boost/decimal/detail/type_traits.hpp | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/boost/decimal/detail/type_traits.hpp b/include/boost/decimal/detail/type_traits.hpp index 0fd70f21..8b86dc55 100644 --- a/include/boost/decimal/detail/type_traits.hpp +++ b/include/boost/decimal/detail/type_traits.hpp @@ -7,6 +7,7 @@ // Extends the current type traits to include our types and __int128s +#include #include #include @@ -150,12 +151,33 @@ struct is_decimal_floating_point { static constexpr bool value = template <> struct is_decimal_floating_point { static constexpr bool value = true; }; +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL +template <> +struct is_decimal_floating_point { static constexpr bool value = true; }; +#endif + template constexpr bool is_decimal_floating_point::value; template constexpr bool is_decimal_floating_point_v = is_decimal_floating_point::value; +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL + +template +struct is_wrapper_type { static constexpr bool value = false; }; + +template <> +struct is_wrapper_type { static constexpr bool value = true; }; + +template +constexpr bool is_wrapper_type::value; + +template +constexpr bool is_wrapper_type_v = is_wrapper_type::value; + +#endif + template struct conjunction : std::true_type {}; From 44042c80c0434c9f0b9d5158525241485f5ccf80 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:02:20 -0500 Subject: [PATCH 31/55] Add new class to forward if applicable --- include/boost/decimal/fwd.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/decimal/fwd.hpp b/include/boost/decimal/fwd.hpp index 67583524..d339fbb5 100644 --- a/include/boost/decimal/fwd.hpp +++ b/include/boost/decimal/fwd.hpp @@ -20,6 +20,10 @@ class decimal64_fast; class decimal128; class decimal128_fast; +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL +class gcc_decimal32; +#endif + } // namespace decimal } // namespace boost From b34245c9461fd303c6369e889c9f2900e7e8ceb7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:02:36 -0500 Subject: [PATCH 32/55] Wrapper types are not constexpr constructible --- include/boost/decimal/detail/to_integral.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/to_integral.hpp b/include/boost/decimal/detail/to_integral.hpp index d4a8efa6..1e7508cb 100644 --- a/include/boost/decimal/detail/to_integral.hpp +++ b/include/boost/decimal/detail/to_integral.hpp @@ -35,8 +35,8 @@ constexpr auto to_integral(Decimal val) noexcept { using Conversion_Type = std::conditional_t::is_signed, std::int64_t, std::uint64_t>; - constexpr Decimal max_target_type { (std::numeric_limits::max)() }; - constexpr Decimal min_target_type { (std::numeric_limits::min)() }; + const Decimal max_target_type { (std::numeric_limits::max)() }; + const Decimal min_target_type { (std::numeric_limits::min)() }; if (isnan(val)) { From 961d13095d3dea8bf0e6380b8475bc2459ef3e66 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:04:17 -0500 Subject: [PATCH 33/55] Add support of to integral method --- include/boost/decimal/gcc_decimal32.hpp | 27 +++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 47006be1..e08fed04 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -95,6 +95,13 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final friend inline auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; friend inline auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool; + // Attempts conversion to integral type: + // If this is nan sets errno to EINVAL and returns 0 + // If this is not representable sets errno to ERANGE and returns 0 + template + friend constexpr auto to_integral(Decimal val) noexcept + BOOST_DECIMAL_REQUIRES_TWO_RETURN(detail::is_decimal_floating_point_v, Decimal, detail::is_integral_v, TargetType, TargetType); + public: using return_type = std::decimal::decimal32; @@ -129,6 +136,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final } // Non-conforming extension: Conversion to integral type. + inline operator unsigned long long() const noexcept; inline operator long long() const noexcept; // 3.2.6 Conversion to generic floating-point type. @@ -194,7 +202,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final { return lhs / rhs.underlying(); } // 3.2.9 Comparison operators. - friend auto operator==(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + friend auto operator==(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool {return lhs.underlying() == rhs.underlying(); } template @@ -207,7 +215,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs == rhs.underlying(); } - friend auto operator!=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + friend auto operator!=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool { return lhs.underlying() != rhs.underlying(); } template @@ -220,7 +228,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs != rhs.underlying(); } - friend auto operator<(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + friend auto operator<(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool {return lhs.underlying() < rhs.underlying(); } template @@ -233,7 +241,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs < rhs.underlying(); } - friend auto operator<=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + friend auto operator<=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool { return lhs.underlying() <= rhs.underlying(); } template @@ -246,7 +254,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs <= rhs.underlying(); } - friend auto operator>(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + friend auto operator>(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool { return lhs.underlying() > rhs.underlying(); } template @@ -259,7 +267,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs > rhs.underlying(); } - friend auto operator>=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type + friend auto operator>=(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool { return lhs.underlying() >= rhs.underlying(); } template @@ -470,13 +478,6 @@ inline gcc_decimal32::operator long double() const noexcept return std::decimal::decimal32_to_long_double(internal_decimal_); } -namespace detail { - -template <> -struct is_decimal_floating_point { static constexpr bool value = true; }; - -}// namespace detial - } // namespace decimal } // namespace boost From 68505eb3ce9bda012d16f3e2d6d379b12c1b9cad Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:09:29 -0500 Subject: [PATCH 34/55] Add additional integer conversion functions --- include/boost/decimal/gcc_decimal32.hpp | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index e08fed04..b262e573 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -138,6 +138,10 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final // Non-conforming extension: Conversion to integral type. inline operator unsigned long long() const noexcept; inline operator long long() const noexcept; + inline operator unsigned long() const noexcept; + inline operator long() const noexcept; + inline operator unsigned() const noexcept; + inline operator int() const noexcept; // 3.2.6 Conversion to generic floating-point type. inline explicit operator float() const noexcept; @@ -429,6 +433,12 @@ inline auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) return rhs.isneg(); } +inline auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool +{ + static_cast(rhs); + return false; +} + inline auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool { static_cast(rhs); @@ -463,6 +473,26 @@ inline gcc_decimal32::operator long long() const noexcept return std::decimal::decimal32_to_long_long(internal_decimal_); } +inline gcc_decimal32::operator unsigned long() const noexcept +{ + return to_integral(*this); +} + +inline gcc_decimal32::operator long() const noexcept +{ + return static_cast(std::decimal::decimal32_to_long_long(internal_decimal_)); +} + +inline gcc_decimal32::operator unsigned() const noexcept +{ + return static_cast(std::decimal::decimal32_to_long_long(internal_decimal_)); +} + +inline gcc_decimal32::operator int() const noexcept +{ + return static_cast(std::decimal::decimal32_to_long_long(internal_decimal_)); +} + inline gcc_decimal32::operator float() const noexcept { return std::decimal::decimal32_to_float(internal_decimal_); From 8ae5ae242f0f5face5636ee6e2dea3e41745f5b3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:53:07 -0500 Subject: [PATCH 35/55] Add the spaceship operator --- include/boost/decimal/gcc_decimal32.hpp | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index b262e573..877233dc 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -284,6 +284,18 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, bool) { return lhs >= rhs.underlying(); } + #ifdef BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR + friend constexpr auto operator<=>(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> std::partial_ordering; + + template + friend constexpr auto operator<=>(gcc_decimal32 lhs, Integer rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering); + + template + friend constexpr auto operator<=>(Integer lhs, gcc_decimal32 rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering); + #endif + // A basic output operator for now template friend auto operator<<(std::basic_ostream& os, const gcc_decimal32& d) -> std::basic_ostream& @@ -508,6 +520,68 @@ inline gcc_decimal32::operator long double() const noexcept return std::decimal::decimal32_to_long_double(internal_decimal_); } +#ifdef BOOST_DECIMAL_HAS_SPACESHIP_OPERATOR + +constexpr auto operator<=>(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> std::partial_ordering +{ + if (lhs < rhs) + { + return std::partial_ordering::less; + } + else if (lhs > rhs) + { + return std::partial_ordering::greater; + } + else if (lhs == rhs) + { + return std::partial_ordering::equivalent; + } + + return std::partial_ordering::unordered; +} + +template +constexpr auto operator<=>(gcc_decimal32 lhs, Integer rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering) +{ + if (lhs < rhs) + { + return std::partial_ordering::less; + } + else if (lhs > rhs) + { + return std::partial_ordering::greater; + } + else if (lhs == rhs) + { + return std::partial_ordering::equivalent; + } + + return std::partial_ordering::unordered; +} + +template +constexpr auto operator<=>(Integer lhs, gcc_decimal32 rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering) +{ + if (lhs < rhs) + { + return std::partial_ordering::less; + } + else if (lhs > rhs) + { + return std::partial_ordering::greater; + } + else if (lhs == rhs) + { + return std::partial_ordering::equivalent; + } + + return std::partial_ordering::unordered; +} + +#endif + } // namespace decimal } // namespace boost From ed53e55e82656d995017f4594d8791b0c625f58f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:53:59 -0500 Subject: [PATCH 36/55] Re-enable all testing --- test/random_gccdecimal32_comp.cpp | 71 ++++++++++++++----------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/test/random_gccdecimal32_comp.cpp b/test/random_gccdecimal32_comp.cpp index 191752c7..7b1cfe6a 100644 --- a/test/random_gccdecimal32_comp.cpp +++ b/test/random_gccdecimal32_comp.cpp @@ -104,7 +104,6 @@ void random_mixed_LT(T lower, T upper) //BOOST_TEST_EQ(std::numeric_limits::quiet_NaN() < T(1), false); } -/* template void random_LE(T lower, T upper) { @@ -129,10 +128,10 @@ void random_LE(T lower, T upper) } } - BOOST_TEST(gcc_decimal32(dist(rng)) <= std::numeric_limits::infinity()); - BOOST_TEST(!(gcc_decimal32(dist(rng)) <= -std::numeric_limits::infinity())); - BOOST_TEST(!(gcc_decimal32(dist(rng)) <= std::numeric_limits::quiet_NaN())); - BOOST_TEST(!(std::numeric_limits::quiet_NaN() <= std::numeric_limits::quiet_NaN())); + //BOOST_TEST(gcc_decimal32(dist(rng)) <= std::numeric_limits::infinity()); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) <= -std::numeric_limits::infinity())); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) <= std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(std::numeric_limits::quiet_NaN() <= std::numeric_limits::quiet_NaN())); } template @@ -159,9 +158,9 @@ void random_mixed_LE(T lower, T upper) } } - BOOST_TEST(dist(rng) <= std::numeric_limits::infinity()); - BOOST_TEST(!(dist(rng) <= -std::numeric_limits::infinity())); - BOOST_TEST(!(dist(rng) <= std::numeric_limits::quiet_NaN())); + //BOOST_TEST(dist(rng) <= std::numeric_limits::infinity()); + //BOOST_TEST(!(dist(rng) <= -std::numeric_limits::infinity())); + //BOOST_TEST(!(dist(rng) <= std::numeric_limits::quiet_NaN())); } template @@ -188,10 +187,10 @@ void random_GT(T lower, T upper) } } - BOOST_TEST(!(gcc_decimal32(dist(rng)) > std::numeric_limits::infinity())); - BOOST_TEST((gcc_decimal32(dist(rng)) > -std::numeric_limits::infinity())); - BOOST_TEST(!(gcc_decimal32(dist(rng)) > std::numeric_limits::quiet_NaN())); - BOOST_TEST(!(std::numeric_limits::quiet_NaN() > std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) > std::numeric_limits::infinity())); + //BOOST_TEST((gcc_decimal32(dist(rng)) > -std::numeric_limits::infinity())); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) > std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(std::numeric_limits::quiet_NaN() > std::numeric_limits::quiet_NaN())); } template @@ -218,9 +217,9 @@ void random_mixed_GT(T lower, T upper) } } - BOOST_TEST(!(dist(rng) > std::numeric_limits::infinity())); - BOOST_TEST((dist(rng) > -std::numeric_limits::infinity())); - BOOST_TEST(!(dist(rng) > std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(dist(rng) > std::numeric_limits::infinity())); + //BOOST_TEST((dist(rng) > -std::numeric_limits::infinity())); + //BOOST_TEST(!(dist(rng) > std::numeric_limits::quiet_NaN())); } template @@ -247,10 +246,10 @@ void random_GE(T lower, T upper) } } - BOOST_TEST(!(gcc_decimal32(dist(rng)) >= std::numeric_limits::infinity())); - BOOST_TEST((gcc_decimal32(dist(rng)) >= -std::numeric_limits::infinity())); - BOOST_TEST(!(gcc_decimal32(dist(rng)) >= std::numeric_limits::quiet_NaN())); - BOOST_TEST(!(std::numeric_limits::quiet_NaN() >= std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) >= std::numeric_limits::infinity())); + //BOOST_TEST((gcc_decimal32(dist(rng)) >= -std::numeric_limits::infinity())); + //BOOST_TEST(!(gcc_decimal32(dist(rng)) >= std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(std::numeric_limits::quiet_NaN() >= std::numeric_limits::quiet_NaN())); } template @@ -277,9 +276,9 @@ void random_mixed_GE(T lower, T upper) } } - BOOST_TEST(!(dist(rng) >= std::numeric_limits::infinity())); - BOOST_TEST((dist(rng) >= -std::numeric_limits::infinity())); - BOOST_TEST(!(dist(rng) >= std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(dist(rng) >= std::numeric_limits::infinity())); + //BOOST_TEST((dist(rng) >= -std::numeric_limits::infinity())); + //BOOST_TEST(!(dist(rng) >= std::numeric_limits::quiet_NaN())); } template @@ -323,7 +322,7 @@ void random_EQ(T lower, T upper) } } - BOOST_TEST(!(std::numeric_limits::quiet_NaN() == std::numeric_limits::quiet_NaN())); + //BOOST_TEST(!(std::numeric_limits::quiet_NaN() == std::numeric_limits::quiet_NaN())); } template @@ -370,14 +369,14 @@ void random_mixed_EQ(T lower, T upper) } // Edge Cases - BOOST_TEST_EQ(gcc_decimal32(1), T(1)); - BOOST_TEST_EQ(gcc_decimal32(10), T(10)); - BOOST_TEST_EQ(gcc_decimal32(100), T(100)); - BOOST_TEST_EQ(gcc_decimal32(1000), T(1000)); - BOOST_TEST_EQ(gcc_decimal32(10000), T(10000)); - BOOST_TEST_EQ(gcc_decimal32(100000), T(100000)); - BOOST_TEST_EQ(std::numeric_limits::quiet_NaN() == T(1), false); - BOOST_TEST_EQ(std::numeric_limits::infinity() == T(1), false); + //BOOST_TEST_EQ(gcc_decimal32(1), T(1)); + //BOOST_TEST_EQ(gcc_decimal32(10), T(10)); + //BOOST_TEST_EQ(gcc_decimal32(100), T(100)); + //BOOST_TEST_EQ(gcc_decimal32(1000), T(1000)); + //BOOST_TEST_EQ(gcc_decimal32(10000), T(10000)); + //BOOST_TEST_EQ(gcc_decimal32(100000), T(100000)); + //BOOST_TEST_EQ(std::numeric_limits::quiet_NaN() == T(1), false); + //BOOST_TEST_EQ(std::numeric_limits::infinity() == T(1), false); } template @@ -404,7 +403,7 @@ void random_NE(T lower, T upper) } } - BOOST_TEST((std::numeric_limits::quiet_NaN() != std::numeric_limits::quiet_NaN())); + //BOOST_TEST((std::numeric_limits::quiet_NaN() != std::numeric_limits::quiet_NaN())); } template @@ -504,8 +503,6 @@ void random_mixed_SPACESHIP(T lower, T upper) } #endif -*/ - int main() { random_LT(std::numeric_limits::min(), std::numeric_limits::max()); @@ -522,7 +519,6 @@ int main() random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); random_mixed_LT(std::numeric_limits::min(), std::numeric_limits::max()); - /* random_LE(std::numeric_limits::min(), std::numeric_limits::max()); random_LE(std::numeric_limits::min(), std::numeric_limits::max()); random_LE(std::numeric_limits::min(), std::numeric_limits::max()); @@ -611,10 +607,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif - constexpr auto pos_zero = boost::decimal::gcc_decimal32{0, 0, false}; - constexpr auto neg_zero = boost::decimal::gcc_decimal32{0, 0, true}; + const auto pos_zero = boost::decimal::gcc_decimal32{0, 0}; + const auto neg_zero = boost::decimal::gcc_decimal32{-0, 0}; BOOST_TEST_EQ(pos_zero, neg_zero); - */ return boost::report_errors(); } From 54e1c8d777407fbee706815665ab425b7fe54661 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 11:57:02 -0500 Subject: [PATCH 37/55] Fix tests for non-GCC toolchains --- test/random_gccdecimal32_comp.cpp | 7 ++++--- test/test_basic_gcc_decimal32.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/test/random_gccdecimal32_comp.cpp b/test/random_gccdecimal32_comp.cpp index 7b1cfe6a..46ad466f 100644 --- a/test/random_gccdecimal32_comp.cpp +++ b/test/random_gccdecimal32_comp.cpp @@ -2,10 +2,11 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "../include/boost/decimal/gcc_decimal32.hpp" +#include -#ifdef BOOST_DECIMAL_HAS_GCC_DECIMAL32 +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL +#include #include #include #include @@ -621,7 +622,7 @@ int main() int main() { std::cerr << "Tests not run" << std::endl; - return 1; + return 0; } #endif diff --git a/test/test_basic_gcc_decimal32.cpp b/test/test_basic_gcc_decimal32.cpp index 9217acf9..c6de7a8a 100644 --- a/test/test_basic_gcc_decimal32.cpp +++ b/test/test_basic_gcc_decimal32.cpp @@ -4,6 +4,10 @@ #define BOOST_DECIMAL_DEBUG_ACCESSORS +#include + +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL + #include #include #include @@ -92,3 +96,12 @@ int main() return boost::report_errors(); } + +#else + +int main() +{ + return 0; +} + +#endif From b8d646864d1882010ba7191a5ad5b551f6d034b4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 13:00:29 -0500 Subject: [PATCH 38/55] Configure using GCC internal macro --- 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 c58d86de..c5e3b35d 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -360,7 +360,7 @@ typedef unsigned __int128 uint128_t; # endif #endif -#if __has_include() && defined(__GNUC__) && __GNUC__ >= 7 +#if __has_include() && defined(_GLIBCXX_USE_DECIMAL_FLOAT) # define BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL #endif From 638e1908ec6e08f60b3013bd5d7de10a3b9a1168 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 13:26:37 -0500 Subject: [PATCH 39/55] Add big endian bit masks --- include/boost/decimal/gcc_decimal32.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 877233dc..dbb1bdf2 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -37,6 +37,8 @@ namespace detail { // // Only is the type different in steering 11 which yields significand 100 + 21 bits giving us our 24 total bits of precision +#ifdef BOOST_DECIMAL_ENDIAN_LITTLE_BYTE + BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_sign_mask = UINT32_C(0b10000000000000000000000000000000); BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_steering_bits_mask = UINT32_C(0b01100000000000000000000000000000); @@ -50,6 +52,25 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_exp_mask = UINT32_C(0b0 BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_significand_mask = UINT32_C(0b00000000011111111111111111111111); BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_significand_mask = UINT32_C(0b00000000000111111111111111111111); + +#else + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_sign_mask = UINT32_C(0b00000000000000000000000000000001); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_steering_bits_mask = UINT32_C(0b00000000000000000000000000000110); + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_00_steering_bits = UINT32_C(0); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_steering_bits = UINT32_C(0b00000000000000000000000000000100); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_10_steering_bits = UINT32_C(0b00000000000000000000000000000010); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_steering_bits = gccd32_steering_bits_mask; + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_exp_mask = UINT32_C(0b00000000000000000000000111111110); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_exp_mask = UINT32_C(0b00000000000000000000011111111000); + +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_significand_mask = UINT32_C(0b11111111111111111111111000000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_significand_mask = UINT32_C(0b11111111111111111111100000000000); + +#endif + } // namespace detail // This type is a wrapper around gcc std::decimal::decimal32 to allow it to use From cbd1769627b74efd30195580d0bb42a5c59548a3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 13:59:16 -0500 Subject: [PATCH 40/55] Include GCC compiler check too --- 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 c5e3b35d..43b3e524 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -360,7 +360,7 @@ typedef unsigned __int128 uint128_t; # endif #endif -#if __has_include() && defined(_GLIBCXX_USE_DECIMAL_FLOAT) +#if __has_include() && defined(_GLIBCXX_USE_DECIMAL_FLOAT) && defined(__GNUC__) && __GNUC__ >= 7 # define BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL #endif From aebac4a3cd78a2f814cf14117dc336b6cdba3f7c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 14:19:16 -0500 Subject: [PATCH 41/55] Add increment and decrement operators --- include/boost/decimal/gcc_decimal32.hpp | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index dbb1bdf2..eb852339 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -317,6 +317,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering); #endif + // 3.2.2.6 Increment and decrement operators + inline auto operator++() noexcept -> gcc_decimal32&; + inline auto operator++(int) noexcept -> gcc_decimal32; + inline auto operator--() noexcept -> gcc_decimal32&; + inline auto operator--(int) noexcept -> gcc_decimal32; + // A basic output operator for now template friend auto operator<<(std::basic_ostream& os, const gcc_decimal32& d) -> std::basic_ostream& @@ -603,6 +609,30 @@ constexpr auto operator<=>(Integer lhs, gcc_decimal32 rhs) noexcept #endif +inline auto gcc_decimal32::operator++() noexcept -> gcc_decimal32& +{ + internal_decimal_++; + return *this; +} + +inline auto gcc_decimal32::operator++(int) noexcept -> gcc_decimal32 +{ + internal_decimal_++; + return *this; +} + +inline auto gcc_decimal32::operator--() noexcept -> gcc_decimal32& +{ + internal_decimal_--; + return *this; +} + +inline auto gcc_decimal32::operator--(int) noexcept -> gcc_decimal32 +{ + internal_decimal_--; + return *this; +} + } // namespace decimal } // namespace boost From 04dc3ca791d8ae1b4ce18e60ef6d865bd5b32f4e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 14:22:35 -0500 Subject: [PATCH 42/55] Make return types consistent --- include/boost/decimal/gcc_decimal32.hpp | 56 ++++++++++++------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index eb852339..74f318bb 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -125,8 +125,6 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final public: - using return_type = std::decimal::decimal32; - gcc_decimal32() = default; explicit gcc_decimal32(std::decimal::decimal32 decimal) { internal_decimal_ = decimal; } @@ -170,65 +168,65 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final inline explicit operator long double() const noexcept; // 3.2.7 Unary arithmetic operators. - friend return_type operator+(const gcc_decimal32 rhs) { return rhs.underlying(); } - friend return_type operator-(const gcc_decimal32 rhs) { return -rhs.underlying(); } + friend gcc_decimal32 operator+(const gcc_decimal32 rhs) { return gcc_decimal32{rhs.underlying()}; } + friend gcc_decimal32 operator-(const gcc_decimal32 rhs) { return gcc_decimal32{-rhs.underlying()}; } // 3.2.8 Binary arithmetic operators. - friend auto operator+(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type - {return lhs.underlying() + rhs.underlying(); } + friend auto operator+(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> gcc_decimal32 + {return gcc_decimal32{lhs.underlying() + rhs.underlying()}; } template friend auto operator+(gcc_decimal32 lhs, Integral rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs.underlying() + rhs; } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs.underlying() + rhs}; } template friend auto operator+(Integral lhs, gcc_decimal32 rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs + rhs.underlying(); } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs + rhs.underlying()}; } - friend auto operator-(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type - {return lhs.underlying() - rhs.underlying(); } + friend auto operator-(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> gcc_decimal32 + {return gcc_decimal32{lhs.underlying() - rhs.underlying()}; } template friend auto operator-(gcc_decimal32 lhs, Integral rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs.underlying() - rhs; } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs.underlying() - rhs}; } template friend auto operator-(Integral lhs, gcc_decimal32 rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs - rhs.underlying(); } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs - rhs.underlying()}; } - friend auto operator*(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type - {return lhs.underlying() * rhs.underlying(); } + friend auto operator*(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> gcc_decimal32 + { return gcc_decimal32{lhs.underlying() * rhs.underlying()}; } template friend auto operator*(gcc_decimal32 lhs, Integral rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs.underlying() * rhs; } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs.underlying() * rhs}; } template friend auto operator*(Integral lhs, gcc_decimal32 rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs * rhs.underlying(); } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs * rhs.underlying()}; } - friend auto operator/(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> return_type - {return lhs.underlying() / rhs.underlying(); } + friend auto operator/(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> gcc_decimal32 + {return gcc_decimal32{lhs.underlying() / rhs.underlying()}; } template friend auto operator/(gcc_decimal32 lhs, Integral rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs.underlying() / rhs; } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs.underlying() / rhs}; } template friend auto operator/(Integral lhs, gcc_decimal32 rhs) - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, return_type) - { return lhs / rhs.underlying(); } + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integral, gcc_decimal32) + { return gcc_decimal32{lhs / rhs.underlying()}; } // 3.2.9 Comparison operators. friend auto operator==(gcc_decimal32 lhs, gcc_decimal32 rhs) noexcept -> bool - {return lhs.underlying() == rhs.underlying(); } + { return lhs.underlying() == rhs.underlying(); } template friend auto operator==(gcc_decimal32 lhs, Integral rhs) From cc67aa4c88c7b1235a3b6dd27d53826ae58481c9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 14:37:11 -0500 Subject: [PATCH 43/55] Add compound assignment --- include/boost/decimal/gcc_decimal32.hpp | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 74f318bb..3ca86d46 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -321,6 +321,39 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final inline auto operator--() noexcept -> gcc_decimal32&; inline auto operator--(int) noexcept -> gcc_decimal32; + // 3.2.2.7 Compound assignment. + inline auto operator+=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& + { internal_decimal_ += rhs.underlying(); return *this; } + + template + inline auto operator+=(Integer rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + { internal_decimal_ += rhs; return *this; } + + inline auto operator-=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& + { internal_decimal_ -= rhs.underlying(); return *this; } + + template + inline auto operator-=(Integer rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + { internal_decimal_ -= rhs; return *this; } + + template + inline auto operator*=(Integer rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + { internal_decimal_ *= rhs; return *this; } + + inline auto operator*=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& + { internal_decimal_ *= rhs.underlying(); return *this; } + + template + inline auto operator/=(Integer rhs) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + { internal_decimal_ /= rhs; return *this; } + + inline auto operator/=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& + { internal_decimal_ /= rhs.underlying(); return *this; } + // A basic output operator for now template friend auto operator<<(std::basic_ostream& os, const gcc_decimal32& d) -> std::basic_ostream& From 84742c8f60ae118f52c9dc5355f24670ba837e48 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 14:40:01 -0500 Subject: [PATCH 44/55] Update basic compile test --- test/compile_tests/gcc_decimal32.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/compile_tests/gcc_decimal32.cpp b/test/compile_tests/gcc_decimal32.cpp index d680d28b..1da1f0a1 100644 --- a/test/compile_tests/gcc_decimal32.cpp +++ b/test/compile_tests/gcc_decimal32.cpp @@ -2,7 +2,9 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#if defined(__GNUC__) && __GNUC__ >= 5 +#include + +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL #include From 9452cc1a1e10e4cedd41aa0cdbbd8bf3a8a016fd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 15:42:55 -0500 Subject: [PATCH 45/55] Add testing of basic mathematical operators --- test/Jamfile | 1 + test/random_gccdecimal32_math.cpp | 611 ++++++++++++++++++++++++++++++ 2 files changed, 612 insertions(+) create mode 100644 test/random_gccdecimal32_math.cpp diff --git a/test/Jamfile b/test/Jamfile index de252a49..1d18dc10 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -195,3 +195,4 @@ compile compile_tests/gcc_decimal32.cpp ; # Wrapper types run test_basic_gcc_decimal32.cpp ; run random_gccdecimal32_comp.cpp ; +run random_gccdecimal32_math.cpp ; diff --git a/test/random_gccdecimal32_math.cpp b/test/random_gccdecimal32_math.cpp new file mode 100644 index 00000000..64aae4b1 --- /dev/null +++ b/test/random_gccdecimal32_math.cpp @@ -0,0 +1,611 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +#ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL + +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +#include + +using namespace boost::decimal; + +#if !defined(BOOST_DECIMAL_REDUCE_TEST_DEPTH) +static constexpr auto N = static_cast(1024U); // Number of trials +#else +static constexpr auto N = static_cast(1024U >> 4U); // Number of trials +#endif + +// NOLINTNEXTLINE : Seed with a constant for repeatability +static std::mt19937_64 rng(42); // NOSONAR : Global rng is not const + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4146) +#endif + +#if defined(__GNUC__) && __GNUC__ >= 8 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + + +template +void random_addition(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + const gcc_decimal32 res = dec1 + dec2; + const auto res_int = static_cast(res); + + if (!BOOST_TEST_EQ(res_int, val1 + val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << val1 + val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() + gcc_decimal32{0,0})); + BOOST_TEST(isinf(gcc_decimal32{0,0} + std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() + gcc_decimal32{0,0})); + BOOST_TEST(isnan(gcc_decimal32{0,0} + std::numeric_limits::quiet_NaN())); + */ +} + +template +void random_mixed_addition(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T trunc_val_2 {static_cast(gcc_decimal32(val2))}; + + const gcc_decimal32 res = dec1 + trunc_val_2; + const auto res_int = static_cast(res); + + if (!BOOST_TEST_EQ(res_int, val1 + val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << trunc_val_2 + << "\nDec res: " << res + << "\nInt res: " << val1 + val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() + dist(rng))); + BOOST_TEST(isinf(dist(rng) + std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() + dist(rng))); + BOOST_TEST(isnan(dist(rng) + std::numeric_limits::quiet_NaN())); + */ +} + +template +void spot_random_mixed_addition(T lhs, T rhs) +{ + const T val1 {lhs}; + const T val2 {rhs}; + + const gcc_decimal32 dec1 {val1}; + const T trunc_val_2 {static_cast(gcc_decimal32(val2))}; + + const gcc_decimal32 res = dec1 + trunc_val_2; + const auto res_int = static_cast(res); + + if (!BOOST_TEST_EQ(res_int, val1 + val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << trunc_val_2 + << "\nDec res: " << res + << "\nInt res: " << val1 + val2 << std::endl; + // LCOV_EXCL_STOP + } +} + +template +void random_converted_addition(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + // Convert these to and from to ensure rounding + const T val1 {static_cast(gcc_decimal32(dist(rng)))}; + const T val2 {static_cast(gcc_decimal32(dist(rng)))}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + const gcc_decimal32 res {dec1 + dec2}; + const gcc_decimal32 comp_val {val1 + val2}; + + if (!BOOST_TEST_EQ(res, comp_val)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << comp_val << std::endl; + // LCOV_EXCL_STOP + } + } +} + +template +void random_subtraction(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + const gcc_decimal32 res = dec1 - dec2; + const auto res_int = static_cast(res); + + if (!BOOST_TEST_EQ(res_int, val1 - val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << val1 - val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() - gcc_decimal32{0,0})); + BOOST_TEST(isinf(gcc_decimal32{0,0} - std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() - gcc_decimal32{0,0})); + BOOST_TEST(isnan(gcc_decimal32{0,0} - std::numeric_limits::quiet_NaN())); + */ +} + +template +void random_mixed_subtraction(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T trunc_val_2 {static_cast(gcc_decimal32(val2))}; + + const gcc_decimal32 res = dec1 - trunc_val_2; + const auto res_int = static_cast(res); + + if (!BOOST_TEST_EQ(res_int, val1 - val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << trunc_val_2 + << "\nDec res: " << res + << "\nInt res: " << val1 - val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const T trunc_val_1 {static_cast(gcc_decimal32(val1))}; + const gcc_decimal32 dec2 {val2}; + + const gcc_decimal32 res = trunc_val_1 - dec2; + const auto res_int = static_cast(res); + + if (!BOOST_TEST_EQ(res_int, val1 - val2)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << trunc_val_1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << val1 - val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() - dist(rng))); + BOOST_TEST(isinf(dist(rng) - std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() - dist(rng))); + BOOST_TEST(isnan(dist(rng) - std::numeric_limits::quiet_NaN())); + */ +} + +template +void random_multiplication(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + const gcc_decimal32 res {dec1 * dec2}; + const gcc_decimal32 res_int {val1 * val2}; + + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + + if (!BOOST_TEST_EQ(res, res_int)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << val1 * val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() * gcc_decimal32(dist(rng)))); + BOOST_TEST(isinf(gcc_decimal32(dist(rng)) * std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() * gcc_decimal32(dist(rng)))); + BOOST_TEST(isnan(gcc_decimal32(dist(rng)) * std::numeric_limits::quiet_NaN())); + */ +} + +template +void random_mixed_multiplication(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + const gcc_decimal32 res {dec1 * dec2}; + const gcc_decimal32 res_int {val1 * val2}; + + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + + if (!BOOST_TEST_EQ(res, res_int)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << val1 * val2 << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() * dist(rng))); + BOOST_TEST(isinf(dist(rng) * std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() * dist(rng))); + BOOST_TEST(isnan(dist(rng) * std::numeric_limits::quiet_NaN())); + */ +} + +template +void random_division(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const gcc_decimal32 dec2 {val2}; + + const auto res {static_cast(dec1 / dec2)}; + const auto res_int {static_cast(val1) / static_cast(val2)}; + + if (std::isinf(res) && std::isinf(res_int)) + { + } + else if (!BOOST_TEST(abs(res - res_int) < 0.001f)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << static_cast(val1) / static_cast(val2) << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + BOOST_TEST(isinf(std::numeric_limits::infinity() / gcc_decimal32(dist(rng)))); + BOOST_TEST(!isinf(gcc_decimal32(dist(rng)) / std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() / gcc_decimal32(dist(rng)))); + BOOST_TEST(isnan(gcc_decimal32(dist(rng)) / std::numeric_limits::quiet_NaN())); + BOOST_TEST(isinf(gcc_decimal32(dist(rng)) / gcc_decimal32(0))); + */ +} + +template +void random_mixed_division(T lower, T upper) +{ + std::uniform_int_distribution dist(lower, upper); + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const gcc_decimal32 dec1 {val1}; + const T dec2 {static_cast(gcc_decimal32(val2))}; + + const auto res {static_cast(dec1 / dec2)}; + const auto res_int {static_cast(val1) / static_cast(val2)}; + + if (std::isinf(res) && std::isinf(res_int)) + { + } + else if (!BOOST_TEST(abs(res - res_int) < 0.001f)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << static_cast(val1) / static_cast(val2) << std::endl; + // LCOV_EXCL_STOP + } + } + + for (std::size_t i {}; i < N; ++i) + { + const T val1 {dist(rng)}; + const T val2 {dist(rng)}; + + const T dec1 {static_cast(gcc_decimal32(val1))}; + const gcc_decimal32 dec2 {val2}; + + const auto res {static_cast(dec1 / dec2)}; + const auto res_int {static_cast(val1) / static_cast(val2)}; + + if (std::isinf(res) && std::isinf(res_int)) + { + } + else if (!BOOST_TEST(abs(res - res_int) < 0.01)) + { + // LCOV_EXCL_START + std::cerr << "Val 1: " << val1 + << "\nDec 1: " << dec1 + << "\nVal 2: " << val2 + << "\nDec 2: " << dec2 + << "\nDec res: " << res + << "\nInt res: " << static_cast(val1) / static_cast(val2) << std::endl; + // LCOV_EXCL_STOP + } + } + + /* + // Edge cases + const gcc_decimal32 val1 {dist(rng)}; + const gcc_decimal32 zero {0, 0}; + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() / dist(rng))); + BOOST_TEST(isinf(std::numeric_limits::infinity() / dist(rng))); + BOOST_TEST(isnan(dist(rng) / std::numeric_limits::quiet_NaN())); + BOOST_TEST_EQ(abs(dist(rng) / std::numeric_limits::infinity()), zero); + BOOST_TEST(isinf(gcc_decimal32(dist(rng)) / 0)); + BOOST_TEST(isinf(val1 / zero)); + */ +} + +int main() +{ + // Values that won't exceed the range of the significand + // Only positive values + random_addition(0, 5'000'000); + random_addition(0L, 5'000'000L); + random_addition(0LL, 5'000'000LL); + random_mixed_addition(0, 5'000'000); + random_mixed_addition(0L, 5'000'000L); + random_mixed_addition(0LL, 5'000'000LL); + + // Only two negative values + random_addition(-5'000'000, 0); + random_addition(-5'000'000L, 0L); + random_addition(-5'000'000LL, 0LL); + random_mixed_addition(-5'000'000, 0); + random_mixed_addition(-5'000'000L, 0L); + random_mixed_addition(-5'000'000LL, 0LL); + + // Only positive values + random_subtraction(0, 5'000'000); + random_subtraction(0L, 5'000'000L); + random_subtraction(0LL, 5'000'000LL); + random_mixed_subtraction(0, 5'000'000); + random_mixed_subtraction(0L, 5'000'000L); + random_mixed_subtraction(0LL, 5'000'000LL); + + // Only two negative values + random_subtraction(-5'000'000, 0); + random_subtraction(-5'000'000L, 0L); + random_subtraction(-5'000'000LL, 0LL); + random_mixed_subtraction(-5'000'000, 0); + random_mixed_subtraction(-5'000'000L, 0L); + random_mixed_subtraction(-5'000'000LL, 0LL); + + // Mixed Values + random_subtraction(-5'000'000, 5'000'000); + random_subtraction(-5'000'000L, 5'000'000L); + random_subtraction(-5'000'000LL, 5'000'000LL); + random_mixed_subtraction(-5'000'000, 5'000'000); + random_mixed_subtraction(-5'000'000L, 5'000'000L); + random_mixed_subtraction(-5'000'000LL, 5'000'000LL); + + // Anything in range + random_addition(-5'000'000, 5'000'000); + random_addition(-5'000'000L, 5'000'000L); + random_addition(-5'000'000LL, 5'000'000LL); + random_mixed_addition(-5'000'000, 5'000'000); + random_mixed_addition(-5'000'000L, 5'000'000L); + random_mixed_addition(-5'000'000LL, 5'000'000LL); + + // Anything in the domain + random_converted_addition(0, (std::numeric_limits::max)() / 2); + random_converted_addition((std::numeric_limits::min)() / 2, 0); + random_converted_addition((std::numeric_limits::min)() / 2, (std::numeric_limits::max)() / 2); + + // Positive values + const auto sqrt_int_max = static_cast(std::sqrt(static_cast((std::numeric_limits::max)()))); + + random_multiplication(0, 5'000); + random_multiplication(0L, 5'000L); + random_multiplication(0LL, 5'000LL); + random_multiplication(0, sqrt_int_max); + random_mixed_multiplication(0, 5'000); + random_mixed_multiplication(0L, 5'000L); + random_mixed_multiplication(0LL, 5'000LL); + random_mixed_multiplication(0, sqrt_int_max); + + // Only negative values + random_multiplication(-5'000, 0); + random_multiplication(-5'000L, 0L); + random_multiplication(-5'000LL, 0LL); + random_multiplication(-sqrt_int_max, 0); + random_mixed_multiplication(-5'000, 0); + random_mixed_multiplication(-5'000L, 0L); + random_mixed_multiplication(-5'000LL, 0LL); + random_mixed_multiplication(-sqrt_int_max, 0); + + // Mixed values + random_multiplication(-5'000, 5'000); + random_multiplication(-5'000L, 5'000L); + random_multiplication(-5'000LL, 5'000LL); + random_multiplication(-sqrt_int_max, sqrt_int_max); + random_mixed_multiplication(-5'000, 5'000); + random_mixed_multiplication(-5'000L, 5'000L); + random_mixed_multiplication(-5'000LL, 5'000LL); + random_mixed_multiplication(-sqrt_int_max, sqrt_int_max); + + random_division(0, 5'000); + random_division(0L, 5'000L); + random_division(0LL, 5'000LL); + random_division(0, sqrt_int_max); + random_mixed_division(0, 5'000); + random_mixed_division(0L, 5'000L); + random_mixed_division(0LL, 5'000LL); + random_mixed_division(0, sqrt_int_max); + + // Only negative values + random_division(-5'000, 0); + random_division(-5'000L, 0L); + random_division(-5'000LL, 0LL); + random_division(-sqrt_int_max, 0); + random_mixed_division(-5'000, 0); + random_mixed_division(-5'000L, 0L); + random_mixed_division(-5'000LL, 0LL); + random_mixed_division(-sqrt_int_max, 0); + + // Mixed values + random_division(-5'000, 5'000); + random_division(-5'000L, 5'000L); + random_division(-5'000LL, 5'000LL); + random_division(-sqrt_int_max, sqrt_int_max); + random_mixed_division(-5'000, 5'000); + random_mixed_division(-5'000L, 5'000L); + random_mixed_division(-5'000LL, 5'000LL); + random_mixed_division(-sqrt_int_max, sqrt_int_max); + + spot_random_mixed_addition(-653573LL, 1391401LL); + spot_random_mixed_addition(894090LL, -1886315LL); + + return boost::report_errors(); +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#if defined(__GNUC__) && __GNUC__ >= 8 +# pragma GCC diagnostic pop +#endif + +#else + +int main() +{ + return 0; +} + +#endif From a9aae9b2b70173aed40b1d60aa627d4dedf7d873 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 16:23:57 -0500 Subject: [PATCH 46/55] Add non-finite values testing and generation --- test/random_gccdecimal32_math.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/random_gccdecimal32_math.cpp b/test/random_gccdecimal32_math.cpp index 64aae4b1..c620f08d 100644 --- a/test/random_gccdecimal32_math.cpp +++ b/test/random_gccdecimal32_math.cpp @@ -470,6 +470,31 @@ void random_mixed_division(T lower, T upper) */ } +void force_nonfinite() +{ + // INF + gcc_decimal32 val1 {1'000'000}; + + for (int i {}; i < 1000; ++i) + { + val1 *= val1; + } + + std::uint32_t bits {}; + std::memcpy(&bits, &val1, sizeof(std::uint32_t)); + + BOOST_TEST(isinf(val1)); + + // NAN + val1 = 10; + val1 /= gcc_decimal32{0}; + bits = 0U; + + std::memcpy(&bits, &val1, sizeof(std::uint32_t)); + + BOOST_TEST(!isfinite(val1)); +} + int main() { // Values that won't exceed the range of the significand @@ -590,6 +615,8 @@ int main() spot_random_mixed_addition(-653573LL, 1391401LL); spot_random_mixed_addition(894090LL, -1886315LL); + force_nonfinite(); + return boost::report_errors(); } From 2bb13b776ef1c1ae34f6455c6ea406703a8edb19 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 16:24:53 -0500 Subject: [PATCH 47/55] Extract values of non-finites --- include/boost/decimal/gcc_decimal32.hpp | 49 ++++++++++++++++++------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 3ca86d46..c3b4198a 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -71,6 +71,11 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_significand_mask = UINT #endif +// Non-finite values +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_inf = UINT32_C(0x78000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_qnan = UINT32_C(0x7C000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_snan = UINT32_C(0x7E000000); + } // namespace detail // This type is a wrapper around gcc std::decimal::decimal32 to allow it to use @@ -327,7 +332,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template inline auto operator+=(Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, gcc_decimal32&) { internal_decimal_ += rhs; return *this; } inline auto operator-=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& @@ -335,12 +340,12 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template inline auto operator-=(Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, gcc_decimal32&) { internal_decimal_ -= rhs; return *this; } template inline auto operator*=(Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, gcc_decimal32&) { internal_decimal_ *= rhs; return *this; } inline auto operator*=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& @@ -348,7 +353,7 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final template inline auto operator/=(Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32&) + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, gcc_decimal32&) { internal_decimal_ /= rhs; return *this; } inline auto operator/=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& @@ -505,32 +510,48 @@ inline auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) inline auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool { - static_cast(rhs); - return false; + std::uint32_t bits_ {}; + std::memcpy(&bits_, &rhs.internal_decimal_, sizeof(std::uint32_t)); + + return bits_ == detail::gccd32_inf; } inline auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool { - static_cast(rhs); - return false; + std::uint32_t bits_ {}; + std::memcpy(&bits_, &rhs.internal_decimal_, sizeof(std::uint32_t)); + + return bits_ >= detail::gccd32_qnan; } inline auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool { - static_cast(rhs); - return false; + std::uint32_t bits_ {}; + std::memcpy(&bits_, &rhs.internal_decimal_, sizeof(std::uint32_t)); + + return bits_ == detail::gccd32_snan; } inline auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool { - static_cast(rhs); - return true; + std::uint32_t bits_ {}; + std::memcpy(&bits_, &rhs.internal_decimal_, sizeof(std::uint32_t)); + + return bits_ < detail::gccd32_inf; } inline auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (gcc_decimal32 rhs) noexcept -> bool { - static_cast(rhs); - return true; + // Check for de-normals + const auto sig {rhs.full_significand()}; + const auto exp {rhs.unbiased_exponent()}; + + if (exp <= detail::precision_v - 1) + { + return false; + } + + return (sig != 0) && isfinite(rhs); } inline gcc_decimal32::operator unsigned long long() const noexcept From a6e6935afea0b5202060edf1d457df82e28969d4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 28 Jan 2025 16:44:15 -0500 Subject: [PATCH 48/55] Add support for std::numeric_limits --- include/boost/decimal/gcc_decimal32.hpp | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index c3b4198a..80486ba7 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -53,6 +53,10 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_exp_mask = UINT32_C(0b0 BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_significand_mask = UINT32_C(0b00000000011111111111111111111111); BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_significand_mask = UINT32_C(0b00000000000111111111111111111111); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_inf_mask = UINT32_C(0x78000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_qnan_mask = UINT32_C(0x7C000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_snan_mask = UINT32_C(0x7E000000); + #else BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_sign_mask = UINT32_C(0b00000000000000000000000000000001); @@ -69,6 +73,10 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_exp_mask = UINT32_C(0b0 BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_01_significand_mask = UINT32_C(0b11111111111111111111111000000000); BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_11_significand_mask = UINT32_C(0b11111111111111111111100000000000); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_inf_mask = UINT32_C(0b00000000000000000000000000011110); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_qnan_mask = UINT32_C(0b00000000000000000000000000111110); +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t gccd32_snan_mask = UINT32_C(0b00000000000000000000000001111110); + #endif // Non-finite values @@ -688,6 +696,71 @@ inline auto gcc_decimal32::operator--(int) noexcept -> gcc_decimal32 } // namespace decimal } // namespace boost +BOOST_DECIMAL_EXPORT template <> +struct std::numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + + // These members were deprecated in C++23 + #if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L))) + static constexpr std::float_denorm_style has_denorm = std::denorm_present; + static constexpr bool has_denorm_loss = true; + #endif + + static constexpr std::float_round_style round_style = std::round_indeterminate; + static constexpr bool is_iec559 = 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 + static inline auto (min) () -> boost::decimal::gcc_decimal32 { return {1, min_exponent}; } + static inline auto (max) () -> boost::decimal::gcc_decimal32 { return {9'999'999, max_exponent - digits + 1}; } + static inline auto lowest () -> boost::decimal::gcc_decimal32 { return {-9'999'999, max_exponent - digits + 1}; } + static inline auto epsilon () -> boost::decimal::gcc_decimal32 { return {1, -digits + 1}; } + static inline auto round_error () -> boost::decimal::gcc_decimal32 { return epsilon(); } + static inline auto infinity () -> boost::decimal::gcc_decimal32 + { + constexpr std::uint32_t bits_ = boost::decimal::detail::gccd32_inf_mask; + std::decimal::decimal32 val {}; + std::memcpy(&val, &bits_, sizeof(std::uint32_t)); + return boost::decimal::gcc_decimal32{val}; + } + + static inline auto quiet_NaN () -> boost::decimal::gcc_decimal32 + { + constexpr std::uint32_t bits_ = boost::decimal::detail::gccd32_qnan_mask; + std::decimal::decimal32 val {}; + std::memcpy(&val, &bits_, sizeof(std::uint32_t)); + return boost::decimal::gcc_decimal32{val}; + } + + static inline auto signaling_NaN() -> boost::decimal::gcc_decimal32 + { + constexpr std::uint32_t bits_ = boost::decimal::detail::gccd32_snan_mask; + std::decimal::decimal32 val {}; + std::memcpy(&val, &bits_, sizeof(std::uint32_t)); + return boost::decimal::gcc_decimal32{val}; + } + + static inline auto denorm_min () -> boost::decimal::gcc_decimal32 { return {1, boost::decimal::detail::etiny}; } +}; + #else #error "libstdc++ header is required to use this functionality" From 990cc935bb62c06465f658c7ab0506dec08f8f33 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 08:17:33 -0500 Subject: [PATCH 49/55] Ignore class mem-access warning --- include/boost/decimal/gcc_decimal32.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 80486ba7..239d3700 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -734,8 +734,15 @@ struct std::numeric_limits static inline auto lowest () -> boost::decimal::gcc_decimal32 { return {-9'999'999, max_exponent - digits + 1}; } static inline auto epsilon () -> boost::decimal::gcc_decimal32 { return {1, -digits + 1}; } static inline auto round_error () -> boost::decimal::gcc_decimal32 { return epsilon(); } + + #if defined(__GNUC__) && __GNUC__ >= 8 + # pragma GCC diagnostic push + # pragma GCC diagnostic ignored "-Wclass-memaccess" + #endif + static inline auto infinity () -> boost::decimal::gcc_decimal32 { + static_assert(sizeof(std::decimal::decimal32) == sizeof(std::uint32_t), "Decimal32 is an unexpected size."); constexpr std::uint32_t bits_ = boost::decimal::detail::gccd32_inf_mask; std::decimal::decimal32 val {}; std::memcpy(&val, &bits_, sizeof(std::uint32_t)); @@ -744,6 +751,7 @@ struct std::numeric_limits static inline auto quiet_NaN () -> boost::decimal::gcc_decimal32 { + static_assert(sizeof(std::decimal::decimal32) == sizeof(std::uint32_t), "Decimal32 is an unexpected size."); constexpr std::uint32_t bits_ = boost::decimal::detail::gccd32_qnan_mask; std::decimal::decimal32 val {}; std::memcpy(&val, &bits_, sizeof(std::uint32_t)); @@ -752,12 +760,17 @@ struct std::numeric_limits static inline auto signaling_NaN() -> boost::decimal::gcc_decimal32 { + static_assert(sizeof(std::decimal::decimal32) == sizeof(std::uint32_t), "Decimal32 is an unexpected size."); constexpr std::uint32_t bits_ = boost::decimal::detail::gccd32_snan_mask; std::decimal::decimal32 val {}; std::memcpy(&val, &bits_, sizeof(std::uint32_t)); return boost::decimal::gcc_decimal32{val}; } + #if defined(__GNUC__) && __GNUC__ >= 8 + # pragma GCC diagnostic pop + #endif + static inline auto denorm_min () -> boost::decimal::gcc_decimal32 { return {1, boost::decimal::detail::etiny}; } }; From 28d490adc1f94d5b04253053e717114b24870e0e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 09:03:39 -0500 Subject: [PATCH 50/55] Remove workaround ostream operator --- include/boost/decimal/gcc_decimal32.hpp | 29 ------------------------- 1 file changed, 29 deletions(-) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 239d3700..36172acb 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -366,35 +366,6 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final inline auto operator/=(gcc_decimal32 rhs) noexcept -> gcc_decimal32& { internal_decimal_ /= rhs.underlying(); return *this; } - - // A basic output operator for now - template - friend auto operator<<(std::basic_ostream& os, const gcc_decimal32& d) -> std::basic_ostream& - { - if (d.isneg()) - { - os << "-"; - } - else - { - os << "+"; - } - - os << d.full_significand(); - - const auto exp {d.biased_exponent()}; - - if (exp < 0) - { - os << "e-" << exp; - } - else - { - os << "e+" << exp; - } - - return os; - } }; template From d4eda0fabc08802eed61ce9cdc63aed0989abebf Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 09:03:48 -0500 Subject: [PATCH 51/55] Add frexp10 friend --- include/boost/decimal/gcc_decimal32.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/decimal/gcc_decimal32.hpp b/include/boost/decimal/gcc_decimal32.hpp index 36172acb..b0737a98 100644 --- a/include/boost/decimal/gcc_decimal32.hpp +++ b/include/boost/decimal/gcc_decimal32.hpp @@ -136,6 +136,9 @@ BOOST_DECIMAL_EXPORT class gcc_decimal32 final friend constexpr auto to_integral(Decimal val) noexcept BOOST_DECIMAL_REQUIRES_TWO_RETURN(detail::is_decimal_floating_point_v, Decimal, detail::is_integral_v, TargetType, TargetType); + template + friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type; + public: gcc_decimal32() = default; From fcaa1c32f0241726649d59dff6fd4fb3df1ef203 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 09:04:06 -0500 Subject: [PATCH 52/55] Replace constexpr variables with const since no constexpr constructor --- include/boost/decimal/charconv.hpp | 8 ++++---- include/boost/decimal/detail/cmath/acosh.hpp | 2 +- include/boost/decimal/detail/cmath/asinh.hpp | 4 ++-- include/boost/decimal/detail/cmath/atan.hpp | 2 +- include/boost/decimal/detail/cmath/atan2.hpp | 2 +- include/boost/decimal/detail/cmath/atanh.hpp | 4 ++-- include/boost/decimal/detail/cmath/ceil.hpp | 4 ++-- include/boost/decimal/detail/cmath/cos.hpp | 2 +- include/boost/decimal/detail/cmath/cosh.hpp | 4 ++-- include/boost/decimal/detail/cmath/ellint_1.hpp | 8 ++++---- include/boost/decimal/detail/cmath/ellint_2.hpp | 8 ++++---- include/boost/decimal/detail/cmath/erf.hpp | 4 ++-- include/boost/decimal/detail/cmath/exp.hpp | 4 ++-- include/boost/decimal/detail/cmath/expm1.hpp | 4 ++-- include/boost/decimal/detail/cmath/fdim.hpp | 2 +- include/boost/decimal/detail/cmath/floor.hpp | 2 +- include/boost/decimal/detail/cmath/fpclassify.hpp | 2 +- include/boost/decimal/detail/cmath/frexp.hpp | 2 +- include/boost/decimal/detail/cmath/frexp10.hpp | 2 +- include/boost/decimal/detail/cmath/hypot.hpp | 2 +- include/boost/decimal/detail/cmath/impl/ellint_impl.hpp | 4 ++-- include/boost/decimal/detail/cmath/impl/pow_impl.hpp | 4 ++-- include/boost/decimal/detail/cmath/lgamma.hpp | 4 ++-- include/boost/decimal/detail/cmath/log.hpp | 4 ++-- include/boost/decimal/detail/cmath/log10.hpp | 2 +- include/boost/decimal/detail/cmath/log1p.hpp | 2 +- include/boost/decimal/detail/cmath/modf.hpp | 2 +- include/boost/decimal/detail/cmath/pow.hpp | 8 ++++---- include/boost/decimal/detail/cmath/remainder.hpp | 2 +- include/boost/decimal/detail/cmath/remquo.hpp | 2 +- include/boost/decimal/detail/cmath/riemann_zeta.hpp | 2 +- include/boost/decimal/detail/cmath/rint.hpp | 4 ++-- include/boost/decimal/detail/cmath/round.hpp | 4 ++-- include/boost/decimal/detail/cmath/sin.hpp | 2 +- include/boost/decimal/detail/cmath/sinh.hpp | 4 ++-- include/boost/decimal/detail/cmath/sqrt.hpp | 2 +- include/boost/decimal/detail/cmath/tan.hpp | 2 +- include/boost/decimal/detail/cmath/tanh.hpp | 4 ++-- include/boost/decimal/detail/cmath/tgamma.hpp | 2 +- 39 files changed, 66 insertions(+), 66 deletions(-) diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index ecc279d2..6bef449d 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -780,11 +780,11 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_impl(char* first, char* last, TargetDecima } auto abs_value = abs(value); - constexpr auto max_fractional_value = impl::decimal_val_v < 64 ? TargetDecimalType{1, 7} : - impl::decimal_val_v < 128 ? TargetDecimalType{1, 16} : - TargetDecimalType{1, 34}; + const auto max_fractional_value = impl::decimal_val_v < 64 ? TargetDecimalType{1, 7} : + impl::decimal_val_v < 128 ? TargetDecimalType{1, 16} : + TargetDecimalType{1, 34}; - constexpr auto min_fractional_value = TargetDecimalType{1, -4}; + const auto min_fractional_value = TargetDecimalType{1, -4}; // Unspecified precision so we always go with the shortest representation if (precision == -1) diff --git a/include/boost/decimal/detail/cmath/acosh.hpp b/include/boost/decimal/detail/cmath/acosh.hpp index 1a1176a6..797ceb6f 100644 --- a/include/boost/decimal/detail/cmath/acosh.hpp +++ b/include/boost/decimal/detail/cmath/acosh.hpp @@ -54,7 +54,7 @@ constexpr auto acosh_impl(T x) noexcept #endif else { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; if (x < one) { diff --git a/include/boost/decimal/detail/cmath/asinh.hpp b/include/boost/decimal/detail/cmath/asinh.hpp index 118db4a2..e95fc54f 100644 --- a/include/boost/decimal/detail/cmath/asinh.hpp +++ b/include/boost/decimal/detail/cmath/asinh.hpp @@ -35,8 +35,8 @@ constexpr auto asinh_impl(T x) noexcept { // Use (parts of) the implementation of asinh from Boost.Math. - constexpr T zero { 0, 0 }; - constexpr T one { 1, 0 }; + const T zero { 0, 0 }; + const T one { 1, 0 }; if (x < zero) { diff --git a/include/boost/decimal/detail/cmath/atan.hpp b/include/boost/decimal/detail/cmath/atan.hpp index 26fd3edd..cc94cb53 100644 --- a/include/boost/decimal/detail/cmath/atan.hpp +++ b/include/boost/decimal/detail/cmath/atan.hpp @@ -53,7 +53,7 @@ constexpr auto atan_impl(T x) noexcept #endif else { - constexpr T one { 1 }; + const T one { 1 }; if (x <= T { 48 }) { diff --git a/include/boost/decimal/detail/cmath/atan2.hpp b/include/boost/decimal/detail/cmath/atan2.hpp index 144c3c9f..c73334b3 100644 --- a/include/boost/decimal/detail/cmath/atan2.hpp +++ b/include/boost/decimal/detail/cmath/atan2.hpp @@ -103,7 +103,7 @@ constexpr auto atan2_impl(T y, T x) noexcept } else if (fpcx == FP_INFINITE && !signx && isfinitey) { - constexpr T zero { 0, 0 }; + const T zero { 0, 0 }; result = signy ? -zero : zero; } diff --git a/include/boost/decimal/detail/cmath/atanh.hpp b/include/boost/decimal/detail/cmath/atanh.hpp index 7a97483b..8a9931ad 100644 --- a/include/boost/decimal/detail/cmath/atanh.hpp +++ b/include/boost/decimal/detail/cmath/atanh.hpp @@ -33,12 +33,12 @@ constexpr auto atanh_impl(T x) noexcept } else { - constexpr T zero { 0, 0 }; + const T zero { 0, 0 }; const auto b_neg = x < zero; const auto xx = abs(x); - constexpr T one { 1, 0 }; + const T one { 1, 0 }; if (xx > one) { diff --git a/include/boost/decimal/detail/cmath/ceil.hpp b/include/boost/decimal/detail/cmath/ceil.hpp index a82d3862..6a42aad6 100644 --- a/include/boost/decimal/detail/cmath/ceil.hpp +++ b/include/boost/decimal/detail/cmath/ceil.hpp @@ -29,8 +29,8 @@ constexpr auto ceil BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T val) noexcept { using DivType = typename T::significand_type; - constexpr T zero {0, 0}; - constexpr T one {1, 0}; + const T zero {0, 0}; + const T one {1, 0}; const auto fp {fpclassify(val)}; switch (fp) diff --git a/include/boost/decimal/detail/cmath/cos.hpp b/include/boost/decimal/detail/cmath/cos.hpp index 304e2fd4..ef420795 100644 --- a/include/boost/decimal/detail/cmath/cos.hpp +++ b/include/boost/decimal/detail/cmath/cos.hpp @@ -107,7 +107,7 @@ constexpr auto cos_impl(T x) noexcept } else { - constexpr T one { 1 }; + const T one { 1 }; result = one; } diff --git a/include/boost/decimal/detail/cmath/cosh.hpp b/include/boost/decimal/detail/cmath/cosh.hpp index d2f067d1..be77b799 100644 --- a/include/boost/decimal/detail/cmath/cosh.hpp +++ b/include/boost/decimal/detail/cmath/cosh.hpp @@ -29,8 +29,8 @@ constexpr auto cosh_impl(T x) noexcept { const auto fpc = fpclassify(x); - constexpr T zero { 0, 0 }; - constexpr T one { 1, 0 }; + const T zero { 0, 0 }; + const T one { 1, 0 }; auto result = zero; diff --git a/include/boost/decimal/detail/cmath/ellint_1.hpp b/include/boost/decimal/detail/cmath/ellint_1.hpp index 96033fea..dc0b1e4e 100644 --- a/include/boost/decimal/detail/cmath/ellint_1.hpp +++ b/include/boost/decimal/detail/cmath/ellint_1.hpp @@ -34,7 +34,7 @@ template constexpr auto ellint_1_impl(T m, T phi) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T one { 1 }; + const T one { 1 }; T result { }; @@ -47,7 +47,7 @@ constexpr auto ellint_1_impl(T m, T phi) noexcept } else if((fpc_phi == FP_ZERO) && (fpc_m == FP_NORMAL)) { - constexpr T zero { 0 }; + const T zero { 0 }; result = zero; } @@ -132,7 +132,7 @@ template constexpr auto comp_ellint_1_impl(T m) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T one { 1 }; + const T one { 1 }; T result { }; @@ -152,7 +152,7 @@ constexpr auto comp_ellint_1_impl(T m) noexcept } else { - constexpr T zero { 0 }; + const T zero { 0 }; T Fpm { }; diff --git a/include/boost/decimal/detail/cmath/ellint_2.hpp b/include/boost/decimal/detail/cmath/ellint_2.hpp index a84e3555..86e46065 100644 --- a/include/boost/decimal/detail/cmath/ellint_2.hpp +++ b/include/boost/decimal/detail/cmath/ellint_2.hpp @@ -34,7 +34,7 @@ template constexpr auto ellint_2_impl(T m, T phi) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T one { 1 }; + const T one { 1 }; T result { }; @@ -47,7 +47,7 @@ constexpr auto ellint_2_impl(T m, T phi) noexcept } else if((fpc_phi == FP_ZERO) && (fpc_m == FP_NORMAL)) { - constexpr T zero { 0 }; + const T zero { 0 }; result = zero; } @@ -129,7 +129,7 @@ template constexpr auto comp_ellint_2_impl(T m) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T one { 1 }; + const T one { 1 }; T result { }; @@ -149,7 +149,7 @@ constexpr auto comp_ellint_2_impl(T m) noexcept } else { - constexpr T zero { 0 }; + const T zero { 0 }; T Fpm { }; T Km { }; diff --git a/include/boost/decimal/detail/cmath/erf.hpp b/include/boost/decimal/detail/cmath/erf.hpp index 417a0575..8e4f1b4a 100644 --- a/include/boost/decimal/detail/cmath/erf.hpp +++ b/include/boost/decimal/detail/cmath/erf.hpp @@ -102,7 +102,7 @@ constexpr auto erf_series_near_zero_sum(const T &x) noexcept -> T template constexpr auto erf_calc_impl(T z, bool invert) noexcept -> T { - constexpr T zero {0, 0}; + const T zero {0, 0}; if (z < zero) { @@ -232,7 +232,7 @@ constexpr auto erf_calc_impl(T z, bool invert) noexcept -> T T{UINT64_C(8978713707780316114), -22} }; - constexpr T one_and_half {15, -1}; + const T one_and_half {15, -1}; result = Y + tools::evaluate_polynomial(P, T(z - one_and_half)) / tools::evaluate_polynomial(Q, T(z - one_and_half)); } else if (z < T{45, -1}) diff --git a/include/boost/decimal/detail/cmath/exp.hpp b/include/boost/decimal/detail/cmath/exp.hpp index f80eb1b8..7af7f356 100644 --- a/include/boost/decimal/detail/cmath/exp.hpp +++ b/include/boost/decimal/detail/cmath/exp.hpp @@ -30,8 +30,8 @@ constexpr auto exp_impl(T x) noexcept { const auto fpc = fpclassify(x); - constexpr T zero { 0, 0 }; - constexpr T one { 1, 0 }; + const T zero { 0, 0 }; + const T one { 1, 0 }; auto result = zero; diff --git a/include/boost/decimal/detail/cmath/expm1.hpp b/include/boost/decimal/detail/cmath/expm1.hpp index 4c9b0b45..80580934 100644 --- a/include/boost/decimal/detail/cmath/expm1.hpp +++ b/include/boost/decimal/detail/cmath/expm1.hpp @@ -29,8 +29,8 @@ constexpr auto expm1_impl(T x) noexcept { const auto fpc = fpclassify(x); - constexpr T zero { 0, 0 }; - constexpr T one { 1, 0 }; + const T zero { 0, 0 }; + const T one { 1, 0 }; auto result = zero; diff --git a/include/boost/decimal/detail/cmath/fdim.hpp b/include/boost/decimal/detail/cmath/fdim.hpp index b70abc9b..b558ddf8 100644 --- a/include/boost/decimal/detail/cmath/fdim.hpp +++ b/include/boost/decimal/detail/cmath/fdim.hpp @@ -23,7 +23,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto fdim(T x, T y) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T zero {0, 0}; + const T zero {0, 0}; #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(x) || isinf(x)) diff --git a/include/boost/decimal/detail/cmath/floor.hpp b/include/boost/decimal/detail/cmath/floor.hpp index 909af9e2..a4f786de 100644 --- a/include/boost/decimal/detail/cmath/floor.hpp +++ b/include/boost/decimal/detail/cmath/floor.hpp @@ -29,7 +29,7 @@ constexpr auto floor BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T val) noexcept { using DivType = typename T::significand_type; - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T neg_one {1, 0, true}; const auto fp {fpclassify(val)}; diff --git a/include/boost/decimal/detail/cmath/fpclassify.hpp b/include/boost/decimal/detail/cmath/fpclassify.hpp index d75f0970..ea044607 100644 --- a/include/boost/decimal/detail/cmath/fpclassify.hpp +++ b/include/boost/decimal/detail/cmath/fpclassify.hpp @@ -23,7 +23,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto fpclassify BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, T, int) { - constexpr T zero {0, 0}; + const T zero {0, 0}; #ifdef BOOST_DECIMAL_FAST_MATH diff --git a/include/boost/decimal/detail/cmath/frexp.hpp b/include/boost/decimal/detail/cmath/frexp.hpp index ae454ec2..b0ff0cb3 100644 --- a/include/boost/decimal/detail/cmath/frexp.hpp +++ b/include/boost/decimal/detail/cmath/frexp.hpp @@ -28,7 +28,7 @@ constexpr auto frexp_impl(T v, int* expon) noexcept { // This implementation of frexp follows closely that of eval_frexp // in Boost.Multiprecision's cpp_dec_float template class. - constexpr T zero { 0, 0 }; + const T zero { 0, 0 }; auto result_frexp = zero; diff --git a/include/boost/decimal/detail/cmath/frexp10.hpp b/include/boost/decimal/detail/cmath/frexp10.hpp index 76339bae..ddcbd0aa 100644 --- a/include/boost/decimal/detail/cmath/frexp10.hpp +++ b/include/boost/decimal/detail/cmath/frexp10.hpp @@ -28,7 +28,7 @@ namespace decimal { BOOST_DECIMAL_EXPORT template constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type { - constexpr T zero {0, 0}; + const T zero {0, 0}; if (num == zero) { diff --git a/include/boost/decimal/detail/cmath/hypot.hpp b/include/boost/decimal/detail/cmath/hypot.hpp index cb354a37..c5744e36 100644 --- a/include/boost/decimal/detail/cmath/hypot.hpp +++ b/include/boost/decimal/detail/cmath/hypot.hpp @@ -28,7 +28,7 @@ namespace detail { template constexpr auto hypot_impl(T x, T y) noexcept { - constexpr T zero {0, 0}; + const T zero {0, 0}; if (abs(x) == zero #ifndef BOOST_DECIMAL_FAST_MATH diff --git a/include/boost/decimal/detail/cmath/impl/ellint_impl.hpp b/include/boost/decimal/detail/cmath/impl/ellint_impl.hpp index 5d168e2f..d63f0b68 100644 --- a/include/boost/decimal/detail/cmath/impl/ellint_impl.hpp +++ b/include/boost/decimal/detail/cmath/impl/ellint_impl.hpp @@ -67,7 +67,7 @@ constexpr auto agm(T phi, const bool phi_is_pi_half { phi == my_pi_half }; - constexpr T one { 1 }; + const T one { 1 }; const bool has_e { ((pEm != nullptr) || (pEpm != nullptr)) }; @@ -94,7 +94,7 @@ constexpr auto agm(T phi, } else { - constexpr T zero { 0 }; + const T zero { 0 }; constexpr T half { 5 , -1 }; T a0 { one }; diff --git a/include/boost/decimal/detail/cmath/impl/pow_impl.hpp b/include/boost/decimal/detail/cmath/impl/pow_impl.hpp index 30a1700e..d990068d 100644 --- a/include/boost/decimal/detail/cmath/impl/pow_impl.hpp +++ b/include/boost/decimal/detail/cmath/impl/pow_impl.hpp @@ -22,7 +22,7 @@ constexpr auto pow_n_impl(T b, UnsignedIntegralType p) noexcept -> std::enable_i { using local_unsigned_integral_type = UnsignedIntegralType; - constexpr T one { 1, 0 }; + const T one { 1, 0 }; T result { }; @@ -78,7 +78,7 @@ constexpr auto pow_n_impl(T b, UnsignedIntegralType p) noexcept -> std::enable_i template constexpr auto pow_2_impl(int e2) noexcept -> std::enable_if_t, T> { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; T result { }; diff --git a/include/boost/decimal/detail/cmath/lgamma.hpp b/include/boost/decimal/detail/cmath/lgamma.hpp index af53ed2a..e21479ac 100644 --- a/include/boost/decimal/detail/cmath/lgamma.hpp +++ b/include/boost/decimal/detail/cmath/lgamma.hpp @@ -66,13 +66,13 @@ constexpr auto lgamma_impl(T x) noexcept } else if ((is_pure_int) && ((nx == 1) || (nx == 2))) { - constexpr T zero { 0, 0 }; + const T zero { 0, 0 }; result = zero; } else { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; if (signbit(x)) { diff --git a/include/boost/decimal/detail/cmath/log.hpp b/include/boost/decimal/detail/cmath/log.hpp index 87d25d41..5f3d580a 100644 --- a/include/boost/decimal/detail/cmath/log.hpp +++ b/include/boost/decimal/detail/cmath/log.hpp @@ -26,7 +26,7 @@ template constexpr auto log_impl(T x) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; T result { }; @@ -66,7 +66,7 @@ constexpr auto log_impl(T x) noexcept } else { - constexpr T zero { 0 }; + const T zero { 0 }; result = zero; } diff --git a/include/boost/decimal/detail/cmath/log10.hpp b/include/boost/decimal/detail/cmath/log10.hpp index 97100d6d..594378f7 100644 --- a/include/boost/decimal/detail/cmath/log10.hpp +++ b/include/boost/decimal/detail/cmath/log10.hpp @@ -74,7 +74,7 @@ constexpr auto log10_impl(T x) noexcept } else { - constexpr T one { 1 }; + const T one { 1 }; if (x < one) { diff --git a/include/boost/decimal/detail/cmath/log1p.hpp b/include/boost/decimal/detail/cmath/log1p.hpp index 58de2216..e7e9c50c 100644 --- a/include/boost/decimal/detail/cmath/log1p.hpp +++ b/include/boost/decimal/detail/cmath/log1p.hpp @@ -27,7 +27,7 @@ template constexpr auto log1p_impl(T x) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; T result { }; diff --git a/include/boost/decimal/detail/cmath/modf.hpp b/include/boost/decimal/detail/cmath/modf.hpp index a799e5d9..3789c3f0 100644 --- a/include/boost/decimal/detail/cmath/modf.hpp +++ b/include/boost/decimal/detail/cmath/modf.hpp @@ -25,7 +25,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto modf(T x, T* iptr) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T zero {0, 0}; + const T zero {0, 0}; const auto is_neg {x < zero}; if (abs(x) == zero || isinf(x)) diff --git a/include/boost/decimal/detail/cmath/pow.hpp b/include/boost/decimal/detail/cmath/pow.hpp index e9dd2ba4..c8a6cb6d 100644 --- a/include/boost/decimal/detail/cmath/pow.hpp +++ b/include/boost/decimal/detail/cmath/pow.hpp @@ -27,8 +27,8 @@ constexpr auto pow(T b, IntegralType p) noexcept { using local_integral_type = IntegralType; - constexpr T zero { 0, 0 }; - constexpr T one { 1, 0 }; + const T zero { 0, 0 }; + const T one { 1, 0 }; T result { }; @@ -150,7 +150,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto pow(T x, T a) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T zero { 0, 0 }; + const T zero { 0, 0 }; auto result = zero; @@ -162,7 +162,7 @@ constexpr auto pow(T x, T a) noexcept } else { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; const auto fpc_x = fpclassify(x); const auto fpc_a = fpclassify(a); diff --git a/include/boost/decimal/detail/cmath/remainder.hpp b/include/boost/decimal/detail/cmath/remainder.hpp index 8ed8a4d6..e838e664 100644 --- a/include/boost/decimal/detail/cmath/remainder.hpp +++ b/include/boost/decimal/detail/cmath/remainder.hpp @@ -23,7 +23,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto remainder(T x, T y) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T half {5, -1}; #ifndef BOOST_DECIMAL_FAST_MATH diff --git a/include/boost/decimal/detail/cmath/remquo.hpp b/include/boost/decimal/detail/cmath/remquo.hpp index 783aec92..fad6c8bf 100644 --- a/include/boost/decimal/detail/cmath/remquo.hpp +++ b/include/boost/decimal/detail/cmath/remquo.hpp @@ -27,7 +27,7 @@ constexpr auto remquo(T x, T y, int* quo) noexcept using unsigned_significand_type = std::conditional_t::value || std::is_same::value, detail::uint128, std::uint64_t>; - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T half {5, -1}; #ifndef BOOST_DECIMAL_FAST_MATH diff --git a/include/boost/decimal/detail/cmath/riemann_zeta.hpp b/include/boost/decimal/detail/cmath/riemann_zeta.hpp index 21915d65..9f0e703f 100644 --- a/include/boost/decimal/detail/cmath/riemann_zeta.hpp +++ b/include/boost/decimal/detail/cmath/riemann_zeta.hpp @@ -32,7 +32,7 @@ constexpr auto riemann_zeta_impl(T x) noexcept { const auto fpc = fpclassify(x); - constexpr T one { 1, 0 }; + const T one { 1, 0 }; const bool is_neg { signbit(x) }; diff --git a/include/boost/decimal/detail/cmath/rint.hpp b/include/boost/decimal/detail/cmath/rint.hpp index 831f6104..92f885f0 100644 --- a/include/boost/decimal/detail/cmath/rint.hpp +++ b/include/boost/decimal/detail/cmath/rint.hpp @@ -51,7 +51,7 @@ constexpr auto rint_impl(T1& sig, T2 exp, bool sign) template constexpr auto lrint_impl(T num) noexcept -> Int { - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T lmax {(std::numeric_limits::max)()}; constexpr T lmin {(std::numeric_limits::min)()}; @@ -116,7 +116,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto rint(T num) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T max_round_value {1 / std::numeric_limits::epsilon()}; #ifndef BOOST_DECIMAL_FAST_MATH diff --git a/include/boost/decimal/detail/cmath/round.hpp b/include/boost/decimal/detail/cmath/round.hpp index 4d78a0b3..7368e436 100644 --- a/include/boost/decimal/detail/cmath/round.hpp +++ b/include/boost/decimal/detail/cmath/round.hpp @@ -25,7 +25,7 @@ BOOST_DECIMAL_EXPORT template constexpr auto round(T num) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T half {5, -1}; #ifndef BOOST_DECIMAL_FAST_MATH @@ -67,7 +67,7 @@ namespace detail { template constexpr auto int_round_impl(T num) noexcept -> Int { - constexpr T zero {0, 0}; + const T zero {0, 0}; constexpr T lmax {(std::numeric_limits::max)()}; constexpr T lmin {(std::numeric_limits::min)()}; diff --git a/include/boost/decimal/detail/cmath/sin.hpp b/include/boost/decimal/detail/cmath/sin.hpp index d3aea106..00dce2aa 100644 --- a/include/boost/decimal/detail/cmath/sin.hpp +++ b/include/boost/decimal/detail/cmath/sin.hpp @@ -71,7 +71,7 @@ constexpr auto sin_impl(T x) noexcept T r { two_r / 2 }; - constexpr T one { 1 }; + const T one { 1 }; bool do_scaling { two_r > one }; diff --git a/include/boost/decimal/detail/cmath/sinh.hpp b/include/boost/decimal/detail/cmath/sinh.hpp index 98b165a9..4e34a89c 100644 --- a/include/boost/decimal/detail/cmath/sinh.hpp +++ b/include/boost/decimal/detail/cmath/sinh.hpp @@ -29,7 +29,7 @@ constexpr auto sinh_impl(T x) noexcept { const auto fpc = fpclassify(x); - constexpr T zero { 0, 0 }; + const T zero { 0, 0 }; auto result = zero; @@ -58,7 +58,7 @@ constexpr auto sinh_impl(T x) noexcept } else { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; if (x < one) { diff --git a/include/boost/decimal/detail/cmath/sqrt.hpp b/include/boost/decimal/detail/cmath/sqrt.hpp index ac17096f..7ff7b0c2 100644 --- a/include/boost/decimal/detail/cmath/sqrt.hpp +++ b/include/boost/decimal/detail/cmath/sqrt.hpp @@ -63,7 +63,7 @@ constexpr auto sqrt_impl(T x) noexcept const bool is_pure { static_cast(zeros_removal.trimmed_number) == 1U }; - constexpr T one { 1 }; + const T one { 1 }; if(is_pure) { diff --git a/include/boost/decimal/detail/cmath/tan.hpp b/include/boost/decimal/detail/cmath/tan.hpp index 5ec3e2d3..34f48a8c 100644 --- a/include/boost/decimal/detail/cmath/tan.hpp +++ b/include/boost/decimal/detail/cmath/tan.hpp @@ -76,7 +76,7 @@ constexpr auto tan(T x) noexcept constexpr T cbrt_epsilon { cbrt(std::numeric_limits::epsilon()) }; - constexpr T one { 1 }; + const T one { 1 }; constexpr T two { 2 }; switch(n) diff --git a/include/boost/decimal/detail/cmath/tanh.hpp b/include/boost/decimal/detail/cmath/tanh.hpp index 940d7a3a..a1564f78 100644 --- a/include/boost/decimal/detail/cmath/tanh.hpp +++ b/include/boost/decimal/detail/cmath/tanh.hpp @@ -29,8 +29,8 @@ constexpr auto tanh_impl(T x) noexcept { const auto fpc = fpclassify(x); - constexpr T zero { 0, 0 }; - constexpr T one { 1, 0 }; + const T zero { 0, 0 }; + const T one { 1, 0 }; auto result = zero; diff --git a/include/boost/decimal/detail/cmath/tgamma.hpp b/include/boost/decimal/detail/cmath/tgamma.hpp index 35a5c140..b7ce9270 100644 --- a/include/boost/decimal/detail/cmath/tgamma.hpp +++ b/include/boost/decimal/detail/cmath/tgamma.hpp @@ -73,7 +73,7 @@ constexpr auto tgamma_impl(T x) noexcept } else { - constexpr T one { 1, 0 }; + const T one { 1, 0 }; if (is_pure_int) { From 0566e7f3d1fd2d31ae914e480caffb85dba362cf Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 09:07:35 -0500 Subject: [PATCH 53/55] Add proper decimal iostream header --- test/random_gccdecimal32_comp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/random_gccdecimal32_comp.cpp b/test/random_gccdecimal32_comp.cpp index 46ad466f..fe0f46aa 100644 --- a/test/random_gccdecimal32_comp.cpp +++ b/test/random_gccdecimal32_comp.cpp @@ -7,6 +7,7 @@ #ifdef BOOST_DECIMAL_HAS_LIBSTDCPP_DECIMAL #include +#include #include #include #include From 1669933a53faa8d08af2a502f9353cbedb520636 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 09:07:47 -0500 Subject: [PATCH 54/55] Add LCOV exclusions --- test/test_basic_gcc_decimal32.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_basic_gcc_decimal32.cpp b/test/test_basic_gcc_decimal32.cpp index c6de7a8a..c697e184 100644 --- a/test/test_basic_gcc_decimal32.cpp +++ b/test/test_basic_gcc_decimal32.cpp @@ -27,6 +27,7 @@ void compare_bits(long long coeff, int exp) !BOOST_TEST_EQ(dec32_val.unbiased_exponent(), gcc_val.unbiased_exponent()) || !BOOST_TEST_EQ(dec32_val.isneg(), gcc_val.isneg())) { + // LCOV_EXCL_START std::uint32_t boost_bits; std::memcpy(&boost_bits, &dec32_val, sizeof(std::uint32_t)); @@ -37,6 +38,7 @@ void compare_bits(long long coeff, int exp) << " Exp: " << exp << '\n' << "Boost: " << std::bitset<32>(boost_bits) << "\n" << " GCC: " << std::bitset<32>(gcc_bits) << "\n" << std::endl; + // LCOV_EXCL_STOP } // Separate test of the to_components From 460b1b94f21b63ce9e4d82dbe497d5b6b2b7f44f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 29 Jan 2025 11:26:58 -0500 Subject: [PATCH 55/55] Suppress / fix additional test only warnings --- test/random_gccdecimal32_math.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/random_gccdecimal32_math.cpp b/test/random_gccdecimal32_math.cpp index c620f08d..354e1d22 100644 --- a/test/random_gccdecimal32_math.cpp +++ b/test/random_gccdecimal32_math.cpp @@ -17,6 +17,8 @@ #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wfloat-equal" +# pragma GCC diagnostic ignored "-Wfloat-conversion" +# pragma GCC diagnostic ignored "-Wconversion" #endif #include @@ -376,7 +378,7 @@ void random_division(T lower, T upper) if (std::isinf(res) && std::isinf(res_int)) { } - else if (!BOOST_TEST(abs(res - res_int) < 0.001f)) + else if (!BOOST_TEST(std::fabs(res - res_int) < 0.001f)) { // LCOV_EXCL_START std::cerr << "Val 1: " << val1 @@ -417,7 +419,7 @@ void random_mixed_division(T lower, T upper) if (std::isinf(res) && std::isinf(res_int)) { } - else if (!BOOST_TEST(abs(res - res_int) < 0.001f)) + else if (!BOOST_TEST(std::fabs(res - res_int) < 0.001f)) { // LCOV_EXCL_START std::cerr << "Val 1: " << val1 @@ -444,7 +446,7 @@ void random_mixed_division(T lower, T upper) if (std::isinf(res) && std::isinf(res_int)) { } - else if (!BOOST_TEST(abs(res - res_int) < 0.01)) + else if (!BOOST_TEST(std::fabs(res - res_int) < 0.01)) { // LCOV_EXCL_START std::cerr << "Val 1: " << val1