diff --git a/include/boost/decimal/decimal128_t.hpp b/include/boost/decimal/decimal128_t.hpp index dab83bd8d..6e9693511 100644 --- a/include/boost/decimal/decimal128_t.hpp +++ b/include/boost/decimal/decimal128_t.hpp @@ -1709,6 +1709,10 @@ constexpr auto operator-(const decimal128_t& lhs, const decimal128_t& rhs) noexc { return from_bits(detail::d128_nan_mask); } + if (isinf(rhs) && !isnan(lhs)) + { + return -rhs; + } return detail::check_non_finite(lhs, rhs); } @@ -1755,6 +1759,11 @@ constexpr auto operator-(const Integer lhs, const decimal128_t rhs) noexcept #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(rhs)) { + if (isinf(rhs)) + { + return -rhs; + } + return detail::check_non_finite(rhs); } #endif diff --git a/include/boost/decimal/decimal32_t.hpp b/include/boost/decimal/decimal32_t.hpp index c3e285db9..0018665b6 100644 --- a/include/boost/decimal/decimal32_t.hpp +++ b/include/boost/decimal/decimal32_t.hpp @@ -1088,6 +1088,10 @@ constexpr auto operator-(const decimal32_t lhs, const decimal32_t rhs) noexcept { return from_bits(detail::d32_nan_mask); } + if (isinf(rhs) && !isnan(lhs)) + { + return -rhs; + } return detail::check_non_finite(lhs, rhs); } @@ -1144,6 +1148,11 @@ constexpr auto operator-(const Integer lhs, const decimal32_t rhs) noexcept #ifndef BOOST_DECIMAL_FAST_MATH if (!isfinite(rhs)) { + if (isinf(rhs)) + { + return -rhs; + } + return detail::check_non_finite(rhs); } #endif diff --git a/include/boost/decimal/decimal64_t.hpp b/include/boost/decimal/decimal64_t.hpp index e789b8bad..a510705a2 100644 --- a/include/boost/decimal/decimal64_t.hpp +++ b/include/boost/decimal/decimal64_t.hpp @@ -1693,7 +1693,11 @@ constexpr auto operator-(const decimal64_t lhs, const decimal64_t rhs) noexcept { return from_bits(detail::d64_nan_mask); } - + if (isinf(rhs) && !isnan(lhs)) + { + return -rhs; + } + return detail::check_non_finite(lhs, rhs); } #endif @@ -1746,6 +1750,11 @@ constexpr auto operator-(const Integer lhs, const decimal64_t rhs) noexcept #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(rhs)) { + if (isinf(rhs)) + { + return -rhs; + } + return detail::check_non_finite(rhs); } #endif diff --git a/include/boost/decimal/decimal_fast128_t.hpp b/include/boost/decimal/decimal_fast128_t.hpp index e61f9b285..a7d247129 100644 --- a/include/boost/decimal/decimal_fast128_t.hpp +++ b/include/boost/decimal/decimal_fast128_t.hpp @@ -1076,6 +1076,10 @@ constexpr auto operator-(const decimal_fast128_t& lhs, const decimal_fast128_t& { return direct_init_d128(detail::d128_fast_qnan, 0, false); } + if (isinf(rhs) && !isnan(lhs)) + { + return -rhs; + } return detail::check_non_finite(lhs, rhs); } @@ -1113,6 +1117,11 @@ constexpr auto operator-(const Integer lhs, const decimal_fast128_t& rhs) noexce #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(rhs)) { + if (isinf(rhs)) + { + return -rhs; + } + return detail::check_non_finite(rhs); } #endif diff --git a/include/boost/decimal/decimal_fast32_t.hpp b/include/boost/decimal/decimal_fast32_t.hpp index 4380ba94f..9d431766c 100644 --- a/include/boost/decimal/decimal_fast32_t.hpp +++ b/include/boost/decimal/decimal_fast32_t.hpp @@ -1052,6 +1052,10 @@ constexpr auto operator-(const decimal_fast32_t lhs, decimal_fast32_t rhs) noexc { return direct_init(detail::d32_fast_qnan, UINT8_C((0))); } + if (isinf(rhs) && !isnan(lhs)) + { + return -rhs; + } return detail::check_non_finite(lhs, rhs); } @@ -1098,6 +1102,11 @@ constexpr auto operator-(const Integer lhs, const decimal_fast32_t rhs) noexcept #ifndef BOOST_DECIMAL_FAST_MATH if (!isfinite(rhs)) { + if (isinf(rhs)) + { + return -rhs; + } + return detail::check_non_finite(rhs); } #endif diff --git a/include/boost/decimal/decimal_fast64_t.hpp b/include/boost/decimal/decimal_fast64_t.hpp index 43d1ac240..4e258bd6d 100644 --- a/include/boost/decimal/decimal_fast64_t.hpp +++ b/include/boost/decimal/decimal_fast64_t.hpp @@ -1177,6 +1177,10 @@ constexpr auto operator-(const decimal_fast64_t lhs, decimal_fast64_t rhs) noexc { return direct_init_d64(detail::d64_fast_qnan, 0, false); } + if (isinf(rhs) && !isnan(lhs)) + { + return -rhs; + } return detail::check_non_finite(lhs, rhs); } @@ -1223,6 +1227,11 @@ constexpr auto operator-(const Integer lhs, const decimal_fast64_t rhs) noexcept #ifndef BOOST_DECIMAL_FAST_MATH if (not_finite(rhs)) { + if (isinf(rhs)) + { + return -rhs; + } + return detail::check_non_finite(rhs); } #endif diff --git a/test/Jamfile b/test/Jamfile index 1bc5282c5..2696639a1 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -85,6 +85,7 @@ run github_issue_1260.cpp ; run github_issue_1294.cpp ; run github_issue_1299.cpp ; run github_issue_1302.cpp ; +run github_issue_1304.cpp ; run link_1.cpp link_2.cpp link_3.cpp ; run quick.cpp ; diff --git a/test/github_issue_1304.cpp b/test/github_issue_1304.cpp new file mode 100644 index 000000000..a66c307b9 --- /dev/null +++ b/test/github_issue_1304.cpp @@ -0,0 +1,42 @@ +// Copyright 2026 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// See: https://github.com/cppalliance/decimal/issues/1304 + +#include +#include +#include + +using namespace boost::decimal; + +template +void test() +{ + BOOST_TEST_EQ(std::numeric_limits::infinity() - T{1000}, std::numeric_limits::infinity()); + BOOST_TEST_EQ(std::numeric_limits::infinity() - 1000, std::numeric_limits::infinity()); + BOOST_TEST_EQ(-std::numeric_limits::infinity() - T{1000}, -std::numeric_limits::infinity()); + BOOST_TEST_EQ(-std::numeric_limits::infinity() - 1000, -std::numeric_limits::infinity()); + BOOST_TEST_EQ(-T{1000} - std::numeric_limits::infinity(), -std::numeric_limits::infinity()); + BOOST_TEST_EQ(-1000 - std::numeric_limits::infinity(), -std::numeric_limits::infinity()); + BOOST_TEST_EQ(T{1000} - std::numeric_limits::infinity(), -std::numeric_limits::infinity()); + BOOST_TEST_EQ(1000 - std::numeric_limits::infinity(), -std::numeric_limits::infinity()); + + BOOST_TEST(isnan(std::numeric_limits::quiet_NaN() - std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::infinity() - std::numeric_limits::quiet_NaN())); + BOOST_TEST(isnan(std::numeric_limits::signaling_NaN() - std::numeric_limits::infinity())); + BOOST_TEST(isnan(std::numeric_limits::infinity() - std::numeric_limits::signaling_NaN())); +} + +int main() +{ + test(); + test(); + test(); + + test(); + test(); + test(); + + return boost::report_errors(); +}