// // This file is part of // // CTBignum // // C++ Library for Compile-Time and Run-Time Multi-Precision and Modular Arithmetic // // // This file is distributed under the Apache License, Version 2.0. See the LICENSE // file for details. #ifndef CT_DIVISION_HPP #define CT_DIVISION_HPP #include #include #include #include #include #include #include #include #include namespace cbn { template struct DivisionResult { Q quotient; R remainder; }; template constexpr DivisionResult,big_int<1, T>> short_div(big_int u, T v) { using TT = typename dbl_bitlen::type; TT r{0}; big_int q{}; for (int i = M - 1; i >= 0; --i) { TT w = (r << std::numeric_limits::digits) + u[i]; q[i] = w / v; r = w % v; } return {q, {static_cast(r)}}; } template constexpr DivisionResult, big_int> div(big_int u, big_int v) { // Knuth's "Algorithm D" for multiprecision division as described in TAOCP // Volume 2: Seminumerical Algorithms // combined with short division // // input: // u big_int, M>=N // v big_int // // computes: // quotient = floor[ u/v ] // rem = u % v // // returns: // std::pair, big_int>(quotient, rem) using TT = typename dbl_bitlen::type; size_t tight_N = N; while (tight_N > 0 && v[tight_N - 1] == 0) --tight_N; big_int q{}; if (tight_N == 1) { // short division TT r {}; for (int i = M - 1; i >= 0; --i) { TT w = (r << std::numeric_limits::digits) + u[i]; q[i] = w / v[0]; r = w % v[0]; } return {q, {static_cast(r)}}; } uint8_t k = 0; while (v[tight_N - 1] < (static_cast(1) << (std::numeric_limits::digits - 1))) { ++k; v = detail::first(shift_left(v, 1)); } auto us = shift_left(u, k); for (int j = M - tight_N; j >= 0; --j) { TT tmp = us[j + tight_N - 1]; TT tmp2 = us[j + tight_N]; tmp += (tmp2 << std::numeric_limits::digits); TT qhat = tmp / v[tight_N - 1]; TT rhat = tmp % v[tight_N - 1]; auto b = static_cast(1) << std::numeric_limits::digits; while (qhat == b || (qhat * v[tight_N - 2] > (rhat << std::numeric_limits::digits) + us[j + tight_N - 2])) { qhat -= 1; rhat += v[tight_N - 1]; if (rhat >= b) break; } auto true_value = subtract(detail::take(us, j, j + tight_N + 1), mul(v, big_int<1, T>{{static_cast(qhat)}})); if (true_value[tight_N]) { auto corrected = add_ignore_carry(true_value, detail::unary_encoding(tight_N + 1)); auto new_us_part = add_ignore_carry(corrected, detail::pad<2>(v)); for (auto i = 0; i <= tight_N; ++i) us[j + i] = new_us_part[i]; --qhat; } else { for (auto i = 0; i <= tight_N; ++i) us[j + i] = true_value[i]; } q[j] = qhat; } return {q, shift_right(detail::first(us), k) }; } template constexpr auto operator/(big_int a, big_int b) { return div(a, b).quotient; } template constexpr auto operator%(big_int a, big_int b) { return div(a, b).remainder; } } #endif