@@ -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+
86155BOOST_DECIMAL_EXPORT constexpr auto fma (decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32
87156{
88157 return fmad32 (x, y, z);
0 commit comments