Skip to content

Commit 03b63a5

Browse files
authored
Merge pull request #1303 from cppalliance/1302
Fix handling of inf times negative values
2 parents 16c3d27 + 958ff9a commit 03b63a5

File tree

9 files changed

+217
-1
lines changed

9 files changed

+217
-1
lines changed

include/boost/decimal/decimal128_t.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,22 @@ constexpr auto operator*(const decimal128_t& lhs, const decimal128_t& rhs) noexc
17711771
{
17721772
return from_bits(detail::d128_nan_mask);
17731773
}
1774+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs)))
1775+
{
1776+
return signbit(lhs) ? lhs : -lhs;
1777+
}
1778+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs)))
1779+
{
1780+
return signbit(lhs) ? -lhs : lhs;
1781+
}
1782+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs)))
1783+
{
1784+
return signbit(rhs) ? rhs : -rhs;
1785+
}
1786+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs)))
1787+
{
1788+
return signbit(rhs) ? -rhs : rhs;
1789+
}
17741790

17751791
return detail::check_non_finite(lhs, rhs);
17761792
}
@@ -1793,6 +1809,15 @@ constexpr auto operator*(const decimal128_t lhs, const Integer rhs) noexcept
17931809
#ifndef BOOST_DECIMAL_FAST_MATH
17941810
if (not_finite(lhs))
17951811
{
1812+
if (isinf(lhs) && (signbit(lhs) != (rhs < 0)))
1813+
{
1814+
return signbit(lhs) ? lhs : -lhs;
1815+
}
1816+
else if (isinf(lhs) && (signbit(lhs) == (rhs < 0)))
1817+
{
1818+
return signbit(lhs) ? -lhs : lhs;
1819+
}
1820+
17961821
return detail::check_non_finite(lhs);
17971822
}
17981823
#endif

include/boost/decimal/decimal32_t.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,22 @@ constexpr auto operator*(const decimal32_t lhs, const decimal32_t rhs) noexcept
17721772
{
17731773
return from_bits(detail::d32_nan_mask);
17741774
}
1775+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs)))
1776+
{
1777+
return signbit(lhs) ? lhs : -lhs;
1778+
}
1779+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs)))
1780+
{
1781+
return signbit(lhs) ? -lhs : lhs;
1782+
}
1783+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs)))
1784+
{
1785+
return signbit(rhs) ? rhs : -rhs;
1786+
}
1787+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs)))
1788+
{
1789+
return signbit(rhs) ? -rhs : rhs;
1790+
}
17751791

17761792
return detail::check_non_finite(lhs, rhs);
17771793
}
@@ -1793,6 +1809,15 @@ constexpr auto operator*(const decimal32_t lhs, const Integer rhs) noexcept
17931809
#ifndef BOOST_DECIMAL_FAST_MATH
17941810
if (!isfinite(lhs))
17951811
{
1812+
if (isinf(lhs) && (signbit(lhs) != (rhs < 0)))
1813+
{
1814+
return signbit(lhs) ? lhs : -lhs;
1815+
}
1816+
else if (isinf(lhs) && (signbit(lhs) == (rhs < 0)))
1817+
{
1818+
return signbit(lhs) ? -lhs : lhs;
1819+
}
1820+
17961821
return detail::check_non_finite(lhs);
17971822
}
17981823
#endif

include/boost/decimal/decimal64_t.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,22 @@ constexpr auto operator*(const decimal64_t lhs, const decimal64_t rhs) noexcept
17741774
{
17751775
return from_bits(detail::d64_nan_mask);
17761776
}
1777+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs)))
1778+
{
1779+
return signbit(lhs) ? lhs : -lhs;
1780+
}
1781+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs)))
1782+
{
1783+
return signbit(lhs) ? -lhs : lhs;
1784+
}
1785+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs)))
1786+
{
1787+
return signbit(rhs) ? rhs : -rhs;
1788+
}
1789+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs)))
1790+
{
1791+
return signbit(rhs) ? -rhs : rhs;
1792+
}
17771793

17781794
return detail::check_non_finite(lhs, rhs);
17791795
}
@@ -1795,6 +1811,15 @@ constexpr auto operator*(const decimal64_t lhs, const Integer rhs) noexcept
17951811
#ifndef BOOST_DECIMAL_FAST_MATH
17961812
if (not_finite(lhs))
17971813
{
1814+
if (isinf(lhs) && (signbit(lhs) != (rhs < 0)))
1815+
{
1816+
return signbit(lhs) ? lhs : -lhs;
1817+
}
1818+
else if (isinf(lhs) && (signbit(lhs) == (rhs < 0)))
1819+
{
1820+
return signbit(lhs) ? -lhs : lhs;
1821+
}
1822+
17981823
return detail::check_non_finite(lhs);
17991824
}
18001825
#endif

include/boost/decimal/decimal_fast128_t.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,22 @@ constexpr auto operator*(const decimal_fast128_t& lhs, const decimal_fast128_t&
11291129
{
11301130
return direct_init_d128(detail::d128_fast_qnan, 0, false);
11311131
}
1132+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs)))
1133+
{
1134+
return signbit(lhs) ? lhs : -lhs;
1135+
}
1136+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs)))
1137+
{
1138+
return signbit(lhs) ? -lhs : lhs;
1139+
}
1140+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs)))
1141+
{
1142+
return signbit(rhs) ? rhs : -rhs;
1143+
}
1144+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs)))
1145+
{
1146+
return signbit(rhs) ? -rhs : rhs;
1147+
}
11321148

11331149
return detail::check_non_finite(lhs, rhs);
11341150
}
@@ -1147,6 +1163,15 @@ constexpr auto operator*(const decimal_fast128_t& lhs, const Integer rhs) noexce
11471163
#ifndef BOOST_DECIMAL_FAST_MATH
11481164
if (not_finite(lhs))
11491165
{
1166+
if (isinf(lhs) && (signbit(lhs) != (rhs < 0)))
1167+
{
1168+
return signbit(lhs) ? lhs : -lhs;
1169+
}
1170+
else if (isinf(lhs) && (signbit(lhs) == (rhs < 0)))
1171+
{
1172+
return signbit(lhs) ? -lhs : lhs;
1173+
}
1174+
11501175
return detail::check_non_finite(lhs);
11511176
}
11521177
#endif

include/boost/decimal/decimal_fast32_t.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,22 @@ constexpr auto operator*(const decimal_fast32_t lhs, const decimal_fast32_t rhs)
11231123
{
11241124
return direct_init(detail::d32_fast_qnan, UINT8_C(0));
11251125
}
1126+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs)))
1127+
{
1128+
return signbit(lhs) ? lhs : -lhs;
1129+
}
1130+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs)))
1131+
{
1132+
return signbit(lhs) ? -lhs : lhs;
1133+
}
1134+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs)))
1135+
{
1136+
return signbit(rhs) ? rhs : -rhs;
1137+
}
1138+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs)))
1139+
{
1140+
return signbit(rhs) ? -rhs : rhs;
1141+
}
11261142

11271143
return detail::check_non_finite(lhs, rhs);
11281144
}
@@ -1141,6 +1157,15 @@ constexpr auto operator*(const decimal_fast32_t lhs, const Integer rhs) noexcept
11411157
#ifndef BOOST_DECIMAL_FAST_MATH
11421158
if (!isfinite(lhs))
11431159
{
1160+
if (isinf(lhs) && (signbit(lhs) != (rhs < 0)))
1161+
{
1162+
return signbit(lhs) ? lhs : -lhs;
1163+
}
1164+
else if (isinf(lhs) && (signbit(lhs) == (rhs < 0)))
1165+
{
1166+
return signbit(lhs) ? -lhs : lhs;
1167+
}
1168+
11441169
return detail::check_non_finite(lhs);
11451170
}
11461171
#endif

include/boost/decimal/decimal_fast64_t.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,22 @@ constexpr auto operator*(const decimal_fast64_t lhs, const decimal_fast64_t rhs)
12481248
{
12491249
return direct_init_d64(detail::d64_fast_qnan, 0, false);
12501250
}
1251+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) != signbit(rhs)))
1252+
{
1253+
return signbit(lhs) ? lhs : -lhs;
1254+
}
1255+
else if (isinf(lhs) && !isnan(rhs) && (signbit(lhs) == signbit(rhs)))
1256+
{
1257+
return signbit(lhs) ? -lhs : lhs;
1258+
}
1259+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) != signbit(lhs)))
1260+
{
1261+
return signbit(rhs) ? rhs : -rhs;
1262+
}
1263+
else if (isinf(rhs) && !isnan(lhs) && (signbit(rhs) == signbit(lhs)))
1264+
{
1265+
return signbit(rhs) ? -rhs : rhs;
1266+
}
12511267

12521268
return detail::check_non_finite(lhs, rhs);
12531269
}
@@ -1266,6 +1282,15 @@ constexpr auto operator*(const decimal_fast64_t lhs, const Integer rhs) noexcept
12661282
#ifndef BOOST_DECIMAL_FAST_MATH
12671283
if (not_finite(lhs))
12681284
{
1285+
if (isinf(lhs) && (signbit(lhs) != (rhs < 0)))
1286+
{
1287+
return signbit(lhs) ? lhs : -lhs;
1288+
}
1289+
else if (isinf(lhs) && (signbit(lhs) == (rhs < 0)))
1290+
{
1291+
return signbit(lhs) ? -lhs : lhs;
1292+
}
1293+
12691294
return detail::check_non_finite(lhs);
12701295
}
12711296
#endif

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ run github_issue_1174.cpp ;
8484
run github_issue_1260.cpp ;
8585
run github_issue_1294.cpp ;
8686
run github_issue_1299.cpp ;
87+
run github_issue_1302.cpp ;
8788

8889
run link_1.cpp link_2.cpp link_3.cpp ;
8990
run quick.cpp ;

test/github_issue_1302.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2026 Matt Borland
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
//
5+
// See: https://github.com/cppalliance/decimal/issues/1294
6+
7+
#include <boost/decimal.hpp>
8+
#include <boost/core/lightweight_test.hpp>
9+
#include <limits>
10+
11+
using namespace boost::decimal;
12+
13+
template <typename T>
14+
void test()
15+
{
16+
// Positive LHS, Positive RHS
17+
BOOST_TEST_EQ(std::numeric_limits<T>::infinity() * std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
18+
BOOST_TEST_EQ(std::numeric_limits<T>::infinity() * T{1000}, std::numeric_limits<T>::infinity());
19+
BOOST_TEST_EQ(std::numeric_limits<T>::infinity() * 1000, std::numeric_limits<T>::infinity());
20+
BOOST_TEST_EQ(T{1000} * std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
21+
BOOST_TEST_EQ(1000 * std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
22+
BOOST_TEST(isnan(std::numeric_limits<T>::infinity() * std::numeric_limits<T>::quiet_NaN()));
23+
BOOST_TEST(isnan(std::numeric_limits<T>::quiet_NaN() * std::numeric_limits<T>::infinity()));
24+
25+
// Positive LHS, Negative RHS
26+
BOOST_TEST_EQ(std::numeric_limits<T>::infinity() * -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
27+
BOOST_TEST_EQ(std::numeric_limits<T>::infinity() * -T{1000}, -std::numeric_limits<T>::infinity());
28+
BOOST_TEST_EQ(std::numeric_limits<T>::infinity() * -1000, -std::numeric_limits<T>::infinity());
29+
BOOST_TEST_EQ(T{1000} * -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
30+
BOOST_TEST_EQ(1000 * -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
31+
BOOST_TEST(isnan(std::numeric_limits<T>::infinity() * -std::numeric_limits<T>::quiet_NaN()));
32+
BOOST_TEST(isnan(std::numeric_limits<T>::quiet_NaN() * -std::numeric_limits<T>::infinity()));
33+
34+
// Negative RHS, positive LHS
35+
BOOST_TEST_EQ(-std::numeric_limits<T>::infinity() * std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
36+
BOOST_TEST_EQ(-std::numeric_limits<T>::infinity() * T{1000}, -std::numeric_limits<T>::infinity());
37+
BOOST_TEST_EQ(-std::numeric_limits<T>::infinity() * 1000, -std::numeric_limits<T>::infinity());
38+
BOOST_TEST_EQ(-T{1000} * std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
39+
BOOST_TEST_EQ(-1000 * std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
40+
BOOST_TEST(isnan(-std::numeric_limits<T>::infinity() * std::numeric_limits<T>::quiet_NaN()));
41+
BOOST_TEST(isnan(-std::numeric_limits<T>::quiet_NaN() * std::numeric_limits<T>::infinity()));
42+
43+
// Negative RHS, Negative RHS
44+
BOOST_TEST_EQ(-std::numeric_limits<T>::infinity() * -std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
45+
BOOST_TEST_EQ(-std::numeric_limits<T>::infinity() * -T{1000}, std::numeric_limits<T>::infinity());
46+
BOOST_TEST_EQ(-std::numeric_limits<T>::infinity() * -1000, std::numeric_limits<T>::infinity());
47+
BOOST_TEST_EQ(-T{1000} * -std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
48+
BOOST_TEST_EQ(-1000 * -std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
49+
BOOST_TEST(isnan(-std::numeric_limits<T>::infinity() * -std::numeric_limits<T>::quiet_NaN()));
50+
BOOST_TEST(isnan(-std::numeric_limits<T>::quiet_NaN() * -std::numeric_limits<T>::infinity()));
51+
52+
}
53+
54+
int main()
55+
{
56+
test<decimal32_t>();
57+
test<decimal64_t>();
58+
test<decimal128_t>();
59+
60+
test<decimal_fast32_t>();
61+
test<decimal_fast64_t>();
62+
test<decimal_fast128_t>();
63+
64+
return boost::report_errors();
65+
}

test/test_to_chars.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void test_error_value(const char* input, chars_format format, int precision = -1
8080
template <typename T>
8181
void test_non_finite_values()
8282
{
83-
std::uniform_real_distribution<float> dist(-1.0, 1.0);
83+
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
8484

8585
const auto formats = {chars_format::fixed, chars_format::scientific, chars_format::general, chars_format::hex};
8686

0 commit comments

Comments
 (0)