Skip to content

Commit 9b78f40

Browse files
committed
Refactor decimal64 fma
1 parent de632a2 commit 9b78f40

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

include/boost/decimal/decimal64.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,6 +2353,7 @@ constexpr auto copysignd64(decimal64 mag, decimal64 sgn) noexcept -> decimal64
23532353
return mag;
23542354
}
23552355

2356+
/*
23562357
constexpr auto fmad64(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64
23572358
{
23582359
// First calculate x * y without rounding
@@ -2417,6 +2418,7 @@ constexpr auto fmad64(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal
24172418
24182419
return {result.sig, result.exp, result.sign};
24192420
}
2421+
*/
24202422

24212423
} //namespace decimal
24222424
} //namespace boost

include/boost/decimal/detail/cmath/fma.hpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,75 @@ constexpr auto fmad32(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal
8383
return {result.sig, result.exp, result.sign};
8484
}
8585

86+
constexpr auto fmad64(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64
87+
{
88+
// First calculate x * y without rounding
89+
constexpr decimal64 zero {0, 0};
90+
91+
const auto res {detail::check_non_finite(x, y)};
92+
if (res != zero)
93+
{
94+
return res;
95+
}
96+
97+
auto sig_lhs {x.full_significand()};
98+
auto exp_lhs {x.biased_exponent()};
99+
detail::normalize<decimal64>(sig_lhs, exp_lhs);
100+
101+
auto sig_rhs {y.full_significand()};
102+
auto exp_rhs {y.biased_exponent()};
103+
detail::normalize<decimal64>(sig_rhs, exp_rhs);
104+
105+
auto mul_result {d64_mul_impl(sig_lhs, exp_lhs, x.isneg(), sig_rhs, exp_rhs, y.isneg())};
106+
const decimal64 dec_result {mul_result.sig, mul_result.exp, mul_result.sign};
107+
108+
const auto res_add {detail::check_non_finite(dec_result, z)};
109+
if (res_add != zero)
110+
{
111+
return res_add;
112+
}
113+
114+
bool lhs_bigger {dec_result > z};
115+
if (dec_result.isneg() && z.isneg())
116+
{
117+
lhs_bigger = !lhs_bigger;
118+
}
119+
bool abs_lhs_bigger {abs(dec_result) > abs(z)};
120+
121+
// To avoid the rounding step we promote the constituent pieces to the next higher type
122+
detail::decimal128_components promoted_mul_result {static_cast<detail::uint128>(mul_result.sig),
123+
mul_result.exp, mul_result.sign};
124+
125+
detail::normalize<decimal128>(promoted_mul_result.sig, promoted_mul_result.exp);
126+
127+
auto sig_z {static_cast<detail::uint128>(z.full_significand())};
128+
auto exp_z {z.biased_exponent()};
129+
detail::normalize<decimal128>(sig_z, exp_z);
130+
detail::decimal128_components z_components {sig_z, exp_z, z.isneg()};
131+
132+
if (!lhs_bigger)
133+
{
134+
detail::swap(promoted_mul_result, z_components);
135+
abs_lhs_bigger = !abs_lhs_bigger;
136+
}
137+
138+
detail::decimal128_components result {};
139+
140+
if (!promoted_mul_result.sign && z_components.sign)
141+
{
142+
result = d128_sub_impl(promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign,
143+
z_components.sig, z_components.exp, z_components.sign,
144+
abs_lhs_bigger);
145+
}
146+
else
147+
{
148+
result = d128_add_impl(promoted_mul_result.sig, promoted_mul_result.exp, promoted_mul_result.sign,
149+
z_components.sig, z_components.exp, z_components.sign);
150+
}
151+
152+
return {result.sig, result.exp, result.sign};
153+
}
154+
86155
BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32
87156
{
88157
return fmad32(x, y, z);

0 commit comments

Comments
 (0)