From 3cea463e619208bacda3b6fd9ca161d4e205314e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 13 Jan 2026 14:39:45 -0500 Subject: [PATCH 1/5] Remove use of bitwise operations from internals --- include/boost/decimal/decimal128_t.hpp | 4 ++++ include/boost/decimal/decimal32_t.hpp | 4 ++++ include/boost/decimal/decimal64_t.hpp | 3 +++ include/boost/decimal/detail/cmath/nan.hpp | 4 ++-- include/boost/decimal/detail/write_payload.hpp | 14 ++++++++------ 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/decimal128_t.hpp b/include/boost/decimal/decimal128_t.hpp index 3017612a7..be2510f84 100644 --- a/include/boost/decimal/decimal128_t.hpp +++ b/include/boost/decimal/decimal128_t.hpp @@ -220,6 +220,10 @@ BOOST_DECIMAL_EXPORT class decimal128_t final friend constexpr auto read_payload(T value) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_ieee_type_v, T, typename T::significand_type); + template + friend constexpr auto detail::write_payload(typename TargetDecimalType::significand_type payload_value) + BOOST_DECIMAL_REQUIRES(detail::is_ieee_type_v, TargetDecimalType); + friend constexpr auto nan_conversion(const decimal128_t value) noexcept -> decimal128_t { constexpr auto convert_nan_mask {detail::d128_snan_mask ^ detail::d128_nan_mask}; diff --git a/include/boost/decimal/decimal32_t.hpp b/include/boost/decimal/decimal32_t.hpp index 577ec4546..40bd780a9 100644 --- a/include/boost/decimal/decimal32_t.hpp +++ b/include/boost/decimal/decimal32_t.hpp @@ -229,6 +229,10 @@ BOOST_DECIMAL_EXPORT class decimal32_t final // NOLINT(cppcoreguidelines-special friend constexpr auto read_payload(T value) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_ieee_type_v, T, typename T::significand_type); + template + friend constexpr auto detail::write_payload(typename TargetDecimalType::significand_type payload_value) + BOOST_DECIMAL_REQUIRES(detail::is_ieee_type_v, TargetDecimalType); + friend constexpr auto nan_conversion(const decimal32_t value) noexcept -> decimal32_t { constexpr auto convert_nan_mask {detail::d32_snan_mask ^ detail::d32_nan_mask}; diff --git a/include/boost/decimal/decimal64_t.hpp b/include/boost/decimal/decimal64_t.hpp index 287e2d6ef..b2777019b 100644 --- a/include/boost/decimal/decimal64_t.hpp +++ b/include/boost/decimal/decimal64_t.hpp @@ -238,6 +238,9 @@ BOOST_DECIMAL_EXPORT class decimal64_t final friend constexpr auto read_payload(T value) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_ieee_type_v, T, typename T::significand_type); + template + friend constexpr auto detail::write_payload(typename TargetDecimalType::significand_type payload_value) + BOOST_DECIMAL_REQUIRES(detail::is_ieee_type_v, TargetDecimalType); friend constexpr auto nan_conversion(const decimal64_t value) noexcept -> decimal64_t { diff --git a/include/boost/decimal/detail/cmath/nan.hpp b/include/boost/decimal/detail/cmath/nan.hpp index 5379ed27b..94da957d8 100644 --- a/include/boost/decimal/detail/cmath/nan.hpp +++ b/include/boost/decimal/detail/cmath/nan.hpp @@ -155,11 +155,11 @@ constexpr auto read_payload(const T value) noexcept } else if (issignaling(value)) { - return (value ^ std::numeric_limits::signaling_NaN()).bits_; + return value.bits_ ^ std::numeric_limits::signaling_NaN().bits_; } else { - return (value ^ std::numeric_limits::quiet_NaN()).bits_; + return value.bits_ ^ std::numeric_limits::quiet_NaN().bits_; } } diff --git a/include/boost/decimal/detail/write_payload.hpp b/include/boost/decimal/detail/write_payload.hpp index b289bb6a0..e71f6b439 100644 --- a/include/boost/decimal/detail/write_payload.hpp +++ b/include/boost/decimal/detail/write_payload.hpp @@ -11,6 +11,11 @@ namespace boost { namespace decimal { + +constexpr auto from_bits(const std::uint32_t rhs) noexcept -> decimal32_t; +constexpr auto from_bits(const std::uint64_t rhs) noexcept -> decimal64_t; +constexpr auto from_bits(const int128::uint128_t rhs) noexcept -> decimal128_t; + namespace detail { template @@ -50,16 +55,13 @@ constexpr auto write_payload(typename TargetDecimalType::significand_type payloa constexpr sig_type max_payload_value {(static_cast(1) << significand_field_bits) - 1U}; - constexpr TargetDecimalType zero {}; - constexpr TargetDecimalType zero_bits {zero ^ zero}; - - TargetDecimalType return_value {nan_type}; + auto return_value {nan_type.bits_}; if (payload_value < max_payload_value) { - return_value = (zero_bits | payload_value) | nan_type; + return_value = payload_value | return_value; } - return return_value; + return from_bits(return_value); } } // namespace detail From 0a6c81e7fd10971c59634379b4af8da67dea9d78 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 13 Jan 2026 14:39:59 -0500 Subject: [PATCH 2/5] Remove decimal32 bitwise operators and testing --- include/boost/decimal/decimal32_t.hpp | 153 --------- test/random_decimal32_math.cpp | 452 -------------------------- 2 files changed, 605 deletions(-) diff --git a/include/boost/decimal/decimal32_t.hpp b/include/boost/decimal/decimal32_t.hpp index 40bd780a9..cee82c43e 100644 --- a/include/boost/decimal/decimal32_t.hpp +++ b/include/boost/decimal/decimal32_t.hpp @@ -556,59 +556,6 @@ BOOST_DECIMAL_EXPORT class decimal32_t final // NOLINT(cppcoreguidelines-special BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, std::partial_ordering); #endif - // Bitwise operators - friend constexpr auto operator&(decimal32_t lhs, decimal32_t rhs) noexcept -> decimal32_t; - - template - friend constexpr auto operator&(decimal32_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - template - friend constexpr auto operator&(Integer lhs, decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - friend constexpr auto operator|(decimal32_t lhs, decimal32_t rhs) noexcept -> decimal32_t; - - template - friend constexpr auto operator|(decimal32_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - template - friend constexpr auto operator|(Integer lhs, decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - friend constexpr auto operator^(decimal32_t lhs, decimal32_t rhs) noexcept -> decimal32_t; - - template - friend constexpr auto operator^(decimal32_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - template - friend constexpr auto operator^(Integer lhs, decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - friend constexpr auto operator<<(decimal32_t lhs, decimal32_t rhs) noexcept -> decimal32_t; - - template - friend constexpr auto operator<<(decimal32_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - template - friend constexpr auto operator<<(Integer lhs, decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - friend constexpr auto operator>>(decimal32_t lhs, decimal32_t rhs) noexcept -> decimal32_t; - - template - friend constexpr auto operator>>(decimal32_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - template - friend constexpr auto operator>>(Integer lhs, decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t); - - friend constexpr auto operator~(decimal32_t lhs) noexcept -> decimal32_t; - // extensions // 3.6.4 Same Quantum friend constexpr auto samequantumd32(decimal32_t lhs, decimal32_t rhs) noexcept -> bool; @@ -2199,106 +2146,6 @@ constexpr decimal32_t::operator std::bfloat16_t() const noexcept } #endif -constexpr auto operator&(const decimal32_t lhs, const decimal32_t rhs) noexcept -> decimal32_t -{ - return from_bits(lhs.bits_ & rhs.bits_); -} - -template -constexpr auto operator&(const decimal32_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(lhs.bits_ & static_cast(rhs)); -} - -template -constexpr auto operator&(const Integer lhs, const decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(static_cast(lhs) & rhs.bits_); -} - -constexpr auto operator|(const decimal32_t lhs, const decimal32_t rhs) noexcept -> decimal32_t -{ - return from_bits(lhs.bits_ | rhs.bits_); -} - -template -constexpr auto operator|(const decimal32_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(lhs.bits_ | static_cast(rhs)); -} - -template -constexpr auto operator|(const Integer lhs, const decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(static_cast(lhs) | rhs.bits_); -} - -constexpr auto operator^(const decimal32_t lhs, const decimal32_t rhs) noexcept -> decimal32_t -{ - return from_bits(lhs.bits_ ^ rhs.bits_); -} - -template -constexpr auto operator^(const decimal32_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(lhs.bits_ ^ static_cast(rhs)); -} - -template -constexpr auto operator^(const Integer lhs, const decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(static_cast(lhs) ^ rhs.bits_); -} - -constexpr auto operator<<(const decimal32_t lhs, const decimal32_t rhs) noexcept -> decimal32_t -{ - return from_bits(lhs.bits_ << rhs.bits_); -} - -template -constexpr auto operator<<(const decimal32_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(lhs.bits_ << static_cast(rhs)); -} - -template -constexpr auto operator<<(const Integer lhs, const decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(static_cast(lhs) << rhs.bits_); -} - -constexpr auto operator>>(const decimal32_t lhs, const decimal32_t rhs) noexcept -> decimal32_t -{ - return from_bits(lhs.bits_ >> rhs.bits_); -} - -template -constexpr auto operator>>(const decimal32_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(lhs.bits_ >> static_cast(rhs)); -} - -template -constexpr auto operator>>(const Integer lhs, const decimal32_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_t) -{ - return from_bits(static_cast(lhs) >> rhs.bits_); -} - -constexpr auto operator~(const decimal32_t lhs) noexcept -> decimal32_t -{ - return from_bits(~lhs.bits_); -} - // 3.6.4 // Effects: determines if the quantum exponents of x and y are the same. // If both x and y are NaN, or infinity, they have the same quantum exponents; diff --git a/test/random_decimal32_math.cpp b/test/random_decimal32_math.cpp index 96efa9172..b2164039c 100644 --- a/test/random_decimal32_math.cpp +++ b/test/random_decimal32_math.cpp @@ -451,446 +451,6 @@ void random_mixed_division(T lower, T upper) BOOST_TEST(isinf(val1 / zero)); } -void random_and() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 & dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_and() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 & val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {val1 & dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_or() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 | dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_or() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 | val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {val1 | dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 ^ dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 ^ val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {val1 ^ dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_left_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 << dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_left_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 << val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {val1 << dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_right_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 >> dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_right_shift() -{ - std::uniform_int_distribution dist(0, 5); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint32_t)); - - const decimal32_t res {dec1 >> val2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal32_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint32_t)); - - const decimal32_t res {val1 >> dec2}; - std::uint32_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint32_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - template void spot_mixed_division(T val1, T val2) { @@ -1063,18 +623,6 @@ int main() random_mixed_division(-5'000LL, 5'000LL); random_mixed_division(-sqrt_int_max, sqrt_int_max); - // Bitwise operators - random_and(); - random_mixed_and(); - random_or(); - random_mixed_or(); - random_xor(); - random_mixed_xor(); - random_left_shift(); - random_mixed_left_shift(); - random_right_shift(); - random_mixed_right_shift(); - spot_random_mixed_addition(-653573LL, 1391401LL); spot_random_mixed_addition(894090LL, -1886315LL); From 6a6be029f886a955919b0df21302138ec826309b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 13 Jan 2026 14:42:08 -0500 Subject: [PATCH 3/5] Remove decimal64 bitwise operators and testing --- include/boost/decimal/decimal64_t.hpp | 153 --------- test/random_decimal64_math.cpp | 452 -------------------------- 2 files changed, 605 deletions(-) diff --git a/include/boost/decimal/decimal64_t.hpp b/include/boost/decimal/decimal64_t.hpp index b2777019b..e0ce9e5fa 100644 --- a/include/boost/decimal/decimal64_t.hpp +++ b/include/boost/decimal/decimal64_t.hpp @@ -578,59 +578,6 @@ BOOST_DECIMAL_EXPORT class decimal64_t final // 3.6.6 Quantize friend constexpr auto quantized64(decimal64_t lhs, decimal64_t rhs) noexcept -> decimal64_t; - // Bit-wise operators - friend constexpr auto operator&(decimal64_t lhs, decimal64_t rhs) noexcept -> decimal64_t; - - template - friend constexpr auto operator&(decimal64_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - template - friend constexpr auto operator&(Integer lhs, decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - friend constexpr auto operator|(decimal64_t lhs, decimal64_t rhs) noexcept -> decimal64_t; - - template - friend constexpr auto operator|(decimal64_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - template - friend constexpr auto operator|(Integer lhs, decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - friend constexpr auto operator^(decimal64_t lhs, decimal64_t rhs) noexcept -> decimal64_t; - - template - friend constexpr auto operator^(decimal64_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - template - friend constexpr auto operator^(Integer lhs, decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - friend constexpr auto operator<<(decimal64_t lhs, decimal64_t rhs) noexcept -> decimal64_t; - - template - friend constexpr auto operator<<(decimal64_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - template - friend constexpr auto operator<<(Integer lhs, decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - friend constexpr auto operator>>(decimal64_t lhs, decimal64_t rhs) noexcept -> decimal64_t; - - template - friend constexpr auto operator>>(decimal64_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - template - friend constexpr auto operator>>(Integer lhs, decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t); - - friend constexpr auto operator~(decimal64_t lhs) noexcept -> decimal64_t; - // functions that need to be friends template friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type; @@ -2108,106 +2055,6 @@ constexpr auto decimal64_t::operator%=(const decimal64_t rhs) noexcept -> decima return *this; } -constexpr auto operator&(const decimal64_t lhs, const decimal64_t rhs) noexcept -> decimal64_t -{ - return from_bits(lhs.bits_ & rhs.bits_); -} - -template -constexpr auto operator&(const decimal64_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(lhs.bits_ & static_cast(rhs)); -} - -template -constexpr auto operator&(const Integer lhs, const decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(static_cast(lhs) & rhs.bits_); -} - -constexpr auto operator|(const decimal64_t lhs, const decimal64_t rhs) noexcept -> decimal64_t -{ - return from_bits(lhs.bits_ | rhs.bits_); -} - -template -constexpr auto operator|(const decimal64_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(lhs.bits_ | static_cast(rhs)); -} - -template -constexpr auto operator|(const Integer lhs, const decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(static_cast(lhs) | rhs.bits_); -} - -constexpr auto operator^(const decimal64_t lhs, const decimal64_t rhs) noexcept -> decimal64_t -{ - return from_bits(lhs.bits_ ^ rhs.bits_); -} - -template -constexpr auto operator^(const decimal64_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(lhs.bits_ ^ static_cast(rhs)); -} - -template -constexpr auto operator^(const Integer lhs, const decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(static_cast(lhs) ^ rhs.bits_); -} - -constexpr auto operator<<(const decimal64_t lhs, const decimal64_t rhs) noexcept -> decimal64_t -{ - return from_bits(lhs.bits_ << rhs.bits_); -} - -template -constexpr auto operator<<(const decimal64_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(lhs.bits_ << static_cast(rhs)); -} - -template -constexpr auto operator<<(const Integer lhs, const decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(static_cast(lhs) << rhs.bits_); -} - -constexpr auto operator>>(const decimal64_t lhs, const decimal64_t rhs) noexcept -> decimal64_t -{ - return from_bits(lhs.bits_ >> rhs.bits_); -} - -template -constexpr auto operator>>(const decimal64_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(lhs.bits_ >> static_cast(rhs)); -} - -template -constexpr auto operator>>(const Integer lhs, const decimal64_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_t) -{ - return from_bits(static_cast(lhs) >> rhs.bits_); -} - -constexpr auto operator~(decimal64_t lhs) noexcept -> decimal64_t -{ - return from_bits(~lhs.bits_); -} - // 3.6.4 // Effects: determines if the quantum exponents of x and y are the same. // If both x and y are NaN, or infinity, they have the same quantum exponents; diff --git a/test/random_decimal64_math.cpp b/test/random_decimal64_math.cpp index 517b8dba6..f8d8232cc 100644 --- a/test/random_decimal64_math.cpp +++ b/test/random_decimal64_math.cpp @@ -506,446 +506,6 @@ void random_mixed_division(T lower, T upper) BOOST_TEST(isinf(val1 / zero)); } -void random_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 & val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {val1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 | val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {val1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 ^ val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {val1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 << val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {val1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal64_t res {dec1 >> val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal64_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal64_t res {val1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - int main() { // Values that won't exceed the range of the significand @@ -1049,18 +609,6 @@ int main() spot_check_mul(27625, 2977); - // Bitwise operators - random_and(); - random_mixed_and(); - random_or(); - random_mixed_or(); - random_xor(); - random_mixed_xor(); - random_left_shift(); - random_mixed_left_shift(); - random_right_shift(); - random_mixed_right_shift(); - spot_mixed_division(4930, -24419); return boost::report_errors(); From b2bcd48f03b276a67d4465191233b483d5dc94c4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 13 Jan 2026 14:43:53 -0500 Subject: [PATCH 4/5] Remove decimal128 bitwise operators and testing --- include/boost/decimal/decimal128_t.hpp | 153 --------- test/random_decimal128_math.cpp | 455 ------------------------- 2 files changed, 608 deletions(-) diff --git a/include/boost/decimal/decimal128_t.hpp b/include/boost/decimal/decimal128_t.hpp index be2510f84..561429f04 100644 --- a/include/boost/decimal/decimal128_t.hpp +++ b/include/boost/decimal/decimal128_t.hpp @@ -559,59 +559,6 @@ BOOST_DECIMAL_EXPORT class decimal128_t final // 3.6.6 Quantize friend constexpr auto quantized128(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t; - // Bit-wise operators - friend constexpr auto operator&(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t; - - template - friend constexpr auto operator&(decimal128_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - template - friend constexpr auto operator&(Integer lhs, decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - friend constexpr auto operator|(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t; - - template - friend constexpr auto operator|(decimal128_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - template - friend constexpr auto operator|(Integer lhs, decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - friend constexpr auto operator^(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t; - - template - friend constexpr auto operator^(decimal128_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - template - friend constexpr auto operator^(Integer lhs, decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - friend constexpr auto operator<<(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t; - - template - friend constexpr auto operator<<(decimal128_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - template - friend constexpr auto operator<<(Integer lhs, decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - friend constexpr auto operator>>(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t; - - template - friend constexpr auto operator>>(decimal128_t lhs, Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - template - friend constexpr auto operator>>(Integer lhs, decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t); - - friend constexpr auto operator~(decimal128_t rhs) noexcept -> decimal128_t; - // functions that need to be friends template friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type; @@ -2175,106 +2122,6 @@ constexpr auto quantized128(const decimal128_t& lhs, const decimal128_t& rhs) no return {lhs.full_significand(), rhs.biased_exponent(), lhs.isneg()}; } -constexpr auto operator&(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t -{ - return from_bits(lhs.bits_ & rhs.bits_); -} - -template -constexpr auto operator&(const decimal128_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(lhs.bits_ & static_cast(rhs)); -} - -template -constexpr auto operator&(const Integer lhs, const decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(static_cast(lhs) & rhs.bits_); -} - -constexpr auto operator|(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t -{ - return from_bits(lhs.bits_ | rhs.bits_); -} - -template -constexpr auto operator|(const decimal128_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(lhs.bits_ | static_cast(rhs)); -} - -template -constexpr auto operator|(const Integer lhs, const decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(static_cast(lhs) | rhs.bits_); -} - -constexpr auto operator^(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t -{ - return from_bits(lhs.bits_ ^ rhs.bits_); -} - -template -constexpr auto operator^(const decimal128_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(lhs.bits_ ^ static_cast(rhs)); -} - -template -constexpr auto operator^(const Integer lhs, const decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(static_cast(lhs) ^ rhs.bits_); -} - -constexpr auto operator<<(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t -{ - return from_bits(lhs.bits_ << static_cast(rhs.bits_)); -} - -template -constexpr auto operator<<(const decimal128_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(lhs.bits_ << static_cast(rhs)); -} - -template -constexpr auto operator<<(const Integer lhs, const decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(static_cast(lhs) << static_cast(rhs.bits_)); -} - -constexpr auto operator>>(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t -{ - return from_bits(lhs.bits_ >> static_cast(rhs.bits_)); -} - -template -constexpr auto operator>>(const decimal128_t lhs, const Integer rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(lhs.bits_ >> static_cast(rhs)); -} - -template -constexpr auto operator>>(const Integer lhs, const decimal128_t rhs) noexcept - BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t) -{ - return from_bits(static_cast(lhs) >> static_cast(rhs.bits_)); -} - -constexpr auto operator~(const decimal128_t lhs) noexcept -> decimal128_t -{ - return from_bits(~lhs.bits_); -} - constexpr auto copysignd128(decimal128_t mag, const decimal128_t sgn) noexcept -> decimal128_t { mag.edit_sign(sgn.isneg()); diff --git a/test/random_decimal128_math.cpp b/test/random_decimal128_math.cpp index 2dd0add32..4549050b3 100644 --- a/test/random_decimal128_math.cpp +++ b/test/random_decimal128_math.cpp @@ -427,446 +427,6 @@ void random_mixed_division(T lower, T upper) BOOST_TEST(isinf(val1 / zero)); } -void random_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_and() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 & val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {val1 & dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 & val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_or() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 | val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {val1 | dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 | val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_xor() -{ - std::uniform_int_distribution dist(0, 9'999'999'999'999'999); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 ^ val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {val1 ^ dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 ^ val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_left_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 << val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {val1 << dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 << val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - -void random_mixed_right_shift() -{ - std::uniform_int_distribution dist(0, 10); - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec1 {}; - std::memcpy(&dec1, &val1, sizeof(std::uint64_t)); - - const decimal128_t res {dec1 >> val2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nDec 1: " << dec1 - << "\nVal 2: " << val2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } - - for (std::size_t i {}; i < N; ++i) - { - const auto val1 {dist(rng)}; - const auto val2 {dist(rng)}; - - decimal128_t dec2 {}; - std::memcpy(&dec2, &val2, sizeof(std::uint64_t)); - - const decimal128_t res {val1 >> dec2}; - std::uint64_t dec_int {}; - std::memcpy(&dec_int, &res, sizeof(std::uint64_t)); - const auto res_int {val1 >> val2}; - - if (!BOOST_TEST_EQ(dec_int, res_int)) - { - // LCOV_EXCL_START - std::cerr << "Val 1: " << val1 - << "\nVal 2: " << val2 - << "\nDec 2: " << dec2 - << "\nDec res: " << res - << "\nInt res: " << res_int << std::endl; - // LCOV_EXCL_STOP - } - } -} - template void test_spot_sub(T lhs, T rhs) { @@ -969,21 +529,6 @@ int main() random_mixed_division(-5'000LL, 5'000LL); random_mixed_division(-sqrt_int_max, sqrt_int_max); - // Bitwise operators - #if BOOST_DECIMAL_ENDIAN_LITTLE_BYTE - random_and(); - random_mixed_and(); - random_or(); - random_mixed_or(); - random_xor(); - random_mixed_xor(); - - random_left_shift(); - random_mixed_left_shift(); - random_right_shift(); - random_mixed_right_shift(); - #endif - test_spot_sub(-813150, -905406); return boost::report_errors(); From 40e0570d19692f1a7ebdb2e5d2902b817025f9c1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 14 Jan 2026 09:06:02 -0500 Subject: [PATCH 5/5] Fix method of clearing bits --- test/test_cmath.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/test_cmath.cpp b/test/test_cmath.cpp index b092d4b8e..d79b38468 100644 --- a/test/test_cmath.cpp +++ b/test/test_cmath.cpp @@ -1254,17 +1254,24 @@ auto test_nan() const std::array sigs {1U, 2U, 3U, 0U, 0U}; constexpr std::array payloads {"1", "2", "3", "Junk", "999999999999999999999999999999999999999999999999999999999999"}; + const T quiet_nan {std::numeric_limits::quiet_NaN()}; + sig_type quiet_nan_bits; + std::memcpy(&quiet_nan_bits, &quiet_nan, sizeof(sig_type)); + + const T signaling_nan {std::numeric_limits::signaling_NaN()}; + sig_type signaling_nan_bits; + std::memcpy(&signaling_nan_bits, &signaling_nan, sizeof(sig_type)); + for (std::size_t i {}; i < sigs.size(); ++i) { const auto payload {nan(payloads[i])}; BOOST_TEST(isnan(payload)); BOOST_TEST(!issignaling(payload)); - const auto removed_nan {payload ^ std::numeric_limits::quiet_NaN()}; - BOOST_TEST(!isnan(removed_nan)); // Check the payload sig_type bits {}; - std::memcpy(&bits, &removed_nan, sizeof(sig_type)); + std::memcpy(&bits, &payload, sizeof(sig_type)); + bits ^= quiet_nan_bits; BOOST_TEST_EQ(bits, sigs[i]); const auto payload_func_bits {read_payload(payload)}; @@ -1276,12 +1283,11 @@ auto test_nan() const auto payload {snan(payloads[i])}; BOOST_TEST(isnan(payload)); BOOST_TEST(issignaling(payload)); - const auto removed_nan {payload ^ std::numeric_limits::signaling_NaN()}; - BOOST_TEST(!isnan(removed_nan)); // Check the payload sig_type bits {}; - std::memcpy(&bits, &removed_nan, sizeof(sig_type)); + std::memcpy(&bits, &payload, sizeof(sig_type)); + bits ^= signaling_nan_bits; BOOST_TEST_EQ(bits, sigs[i]); const auto payload_func_bits {read_payload(payload)};