Skip to content

Commit 8f41872

Browse files
committed
Add new, reduced 32 bit subtraction impl
1 parent 73669da commit 8f41872

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

include/boost/decimal/detail/sub_impl.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,72 @@ namespace boost {
1717
namespace decimal {
1818
namespace detail {
1919

20+
template <typename ReturnType, typename T, typename U>
21+
BOOST_DECIMAL_FORCE_INLINE constexpr auto new_sub_impl(T lhs_sig, U lhs_exp, bool lhs_sign,
22+
T rhs_sig, U rhs_exp, bool rhs_sign,
23+
bool abs_lhs_bigger) noexcept -> ReturnType
24+
{
25+
using sub_type = std::int_fast32_t;
26+
27+
auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp};
28+
auto signed_sig_lhs {detail::make_signed_value(static_cast<sub_type>(lhs_sig), lhs_sign)};
29+
auto signed_sig_rhs {detail::make_signed_value(static_cast<sub_type>(rhs_sig), rhs_sign)};
30+
31+
if (delta_exp > detail::precision + 1)
32+
{
33+
// If the difference in exponents is more than the digits of accuracy
34+
// we return the larger of the two
35+
//
36+
// e.g. 1e20 - 1e-20 = 1e20
37+
return abs_lhs_bigger ? ReturnType{lhs_sig, lhs_exp, false} :
38+
ReturnType{rhs_sig, rhs_exp, true};
39+
}
40+
41+
// The two numbers can be subtracted together without special handling
42+
43+
auto& sig_bigger {abs_lhs_bigger ? signed_sig_lhs : signed_sig_rhs};
44+
auto& exp_bigger {abs_lhs_bigger ? lhs_exp : rhs_exp};
45+
auto& sig_smaller {abs_lhs_bigger ? signed_sig_rhs : signed_sig_lhs};
46+
auto& smaller_sign {abs_lhs_bigger ? rhs_sign : lhs_sign};
47+
48+
if (delta_exp == 1)
49+
{
50+
sig_bigger *= 10;
51+
--delta_exp;
52+
--exp_bigger;
53+
}
54+
else
55+
{
56+
if (delta_exp >= 2)
57+
{
58+
sig_bigger *= 100;
59+
delta_exp -= 2;
60+
exp_bigger -= 2;
61+
}
62+
63+
if (delta_exp > 1)
64+
{
65+
sig_smaller /= pow10(delta_exp - 1);
66+
delta_exp = 1;
67+
}
68+
69+
if (delta_exp == 1)
70+
{
71+
detail::fenv_round(sig_smaller, smaller_sign);
72+
}
73+
}
74+
75+
// Both of the significands are less than 9'999'999, so we can safely
76+
// cast them to signed 32-bit ints to calculate the new significand
77+
const auto new_sig {signed_sig_lhs - signed_sig_rhs};
78+
79+
const auto new_exp {abs_lhs_bigger ? lhs_exp : rhs_exp};
80+
const auto new_sign {new_sig < 0};
81+
const auto res_sig {detail::make_positive_unsigned(new_sig)};
82+
83+
return {res_sig, new_exp, new_sign};
84+
}
85+
2086
template <typename ReturnType, typename T, typename U>
2187
BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T lhs_sig, U lhs_exp, bool lhs_sign,
2288
T rhs_sig, U rhs_exp, bool rhs_sign,

0 commit comments

Comments
 (0)