@@ -340,6 +340,85 @@ constexpr auto d128_add_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
340340 return {new_sig, new_exp, sign};
341341}
342342
343+ template <typename ReturnType, typename T, typename U>
344+ constexpr auto d128_add_impl (T lhs_sig, U lhs_exp, bool lhs_sign,
345+ T rhs_sig, U rhs_exp, bool rhs_sign,
346+ bool abs_lhs_bigger) noexcept -> ReturnType
347+ {
348+ auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp};
349+
350+ #ifdef BOOST_DECIMAL_DEBUG_ADD
351+ std::cerr << " Starting sig lhs: " << lhs_sig
352+ << " \n Starting exp lhs: " << lhs_exp
353+ << " \n Starting sig rhs: " << rhs_sig
354+ << " \n Starting exp rhs: " << rhs_exp << std::endl;
355+ #endif
356+
357+ if (delta_exp > detail::precision_v<decimal128> + 1 )
358+ {
359+ // If the difference in exponents is more than the digits of accuracy
360+ // we return the larger of the two
361+ //
362+ // e.g. 1e20 + 1e-20 = 1e20
363+
364+ return abs_lhs_bigger ? ReturnType{lhs_sig, lhs_exp, lhs_sign} :
365+ ReturnType{rhs_sig, rhs_exp, rhs_sign};
366+ }
367+
368+ // The two numbers can be added together without special handling
369+ //
370+ // If we can add to the lhs sig rather than dividing we can save some precision
371+ // 32-bit signed int can have 9 digits and our normalized significand has 7
372+
373+ auto & sig_bigger {abs_lhs_bigger ? lhs_sig : rhs_sig};
374+ auto & exp_bigger {abs_lhs_bigger ? lhs_exp : rhs_exp};
375+ auto & sig_smaller {abs_lhs_bigger ? rhs_sig : lhs_sig};
376+ auto & sign_smaller {abs_lhs_bigger ? rhs_sign : lhs_sign};
377+ auto & sign_bigger {abs_lhs_bigger ? lhs_sign : rhs_sign};
378+
379+ if (delta_exp <= 2 )
380+ {
381+ sig_bigger *= pow10 (static_cast <uint128>(delta_exp));
382+ exp_bigger -= delta_exp;
383+ delta_exp = 0 ;
384+ }
385+ else
386+ {
387+ sig_bigger *= 100 ;
388+ delta_exp -= 2 ;
389+ exp_bigger -= 2 ;
390+
391+ if (delta_exp > 1 )
392+ {
393+ sig_smaller /= pow10 (static_cast <uint128>(delta_exp - 1 ));
394+ delta_exp = 1 ;
395+ }
396+
397+ if (delta_exp == 1 )
398+ {
399+ detail::fenv_round<decimal128>(sig_smaller, sign_smaller);
400+ }
401+ }
402+
403+ // Cast the results to signed types so that we can apply a sign at the end if necessary
404+ // Both of the significands are maximally 24 bits, so they fit into a 32-bit signed type just fine
405+ auto signed_sig_lhs {detail::make_signed_value (sig_bigger, sign_bigger)};
406+ auto signed_sig_rhs {detail::make_signed_value (sig_smaller, sign_smaller)};
407+
408+ const auto new_sig {signed_sig_lhs + signed_sig_rhs};
409+ const auto new_exp {exp_bigger};
410+ const auto new_sign {new_sig < 0 };
411+ const auto res_sig {detail::make_positive_unsigned (new_sig)};
412+
413+ #ifdef BOOST_DECIMAL_DEBUG_ADD
414+ std::cerr << " Final sig lhs: " << lhs_sig
415+ << " \n Final sig rhs: " << rhs_sig
416+ << " \n Result sig: " << new_sig << std::endl;
417+ #endif
418+
419+ return {res_sig, new_exp, new_sign};
420+ }
421+
343422#ifdef _MSC_VER
344423# pragma warning(pop)
345424#endif
0 commit comments