diff --git a/AK/UFixedBigInt.h b/AK/UFixedBigInt.h index cc35324c8e..29125c0728 100644 --- a/AK/UFixedBigInt.h +++ b/AK/UFixedBigInt.h @@ -37,6 +37,12 @@ struct NumericLimits> { static constexpr bool is_signed() { return false; } }; +template +struct UFixedBigIntMultiplicationResult { + T low; + T high; +}; + template requires(sizeof(T) >= sizeof(u64) && IsUnsigned) class UFixedBigInt { public: @@ -534,6 +540,72 @@ public: return res; } + template + requires(IsSame&& IsSame) constexpr UFixedBigIntMultiplicationResult wide_multiply(U const& other) const + { + auto mult_64_to_128 = [](u64 a, u64 b) -> UFixedBigIntMultiplicationResult { +#ifdef __SIZEOF_INT128__ + unsigned __int128 result = (unsigned __int128)a * b; + u64 low = result; + u64 high = result >> 64; + return { low, high }; +#else + u32 a_low = a; + u32 a_high = (a >> 32); + u32 b_low = b; + u32 b_high = (b >> 32); + + u64 ll_result = (u64)a_low * b_low; + u64 lh_result = (u64)a_low * b_high; + u64 hl_result = (u64)a_high * b_low; + u64 hh_result = (u64)a_high * b_high; + + UFixedBigInt ll { ll_result, 0u }; + UFixedBigInt lh { lh_result << 32, lh_result >> 32 }; + UFixedBigInt hl { hl_result << 32, hl_result >> 32 }; + UFixedBigInt hh { 0u, hh_result }; + + UFixedBigInt result = ll + lh + hl + hh; + return { result.low(), result.high() }; +#endif + }; + + auto ll_result = mult_64_to_128(m_low, other.low()); + auto lh_result = mult_64_to_128(m_low, other.high()); + auto hl_result = mult_64_to_128(m_high, other.low()); + auto hh_result = mult_64_to_128(m_high, other.high()); + + UFixedBigInt ll { R { ll_result.low, ll_result.high }, R { 0u, 0u } }; + UFixedBigInt lh { R { 0u, lh_result.low }, R { lh_result.high, 0u } }; + UFixedBigInt hl { R { 0u, hl_result.low }, R { hl_result.high, 0u } }; + UFixedBigInt hh { R { 0u, 0u }, R { hh_result.low, hh_result.high } }; + + UFixedBigInt result = ll + lh + hl + hh; + return { result.low(), result.high() }; + } + + template + requires(IsSame && sizeof(T) > sizeof(u64)) constexpr UFixedBigIntMultiplicationResult wide_multiply(U const& other) const + { + T left_low = m_low; + T left_high = m_high; + T right_low = other.low(); + T right_high = other.high(); + + auto ll_result = left_low.wide_multiply(right_low); + auto lh_result = left_low.wide_multiply(right_high); + auto hl_result = left_high.wide_multiply(right_low); + auto hh_result = left_high.wide_multiply(right_high); + + UFixedBigInt ll { R { ll_result.low, ll_result.high }, R { 0u, 0u } }; + UFixedBigInt lh { R { 0u, lh_result.low }, R { lh_result.high, 0u } }; + UFixedBigInt hl { R { 0u, hl_result.low }, R { hl_result.high, 0u } }; + UFixedBigInt hh { R { 0u, 0u }, R { hh_result.low, hh_result.high } }; + + UFixedBigInt result = ll + lh + hl + hh; + return { result.low(), result.high() }; + } + template constexpr R operator/(const U& other) const {