// // 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_INVAR_DIV_HPP #define CT_INVAR_DIV_HPP #include #include #include #include #include #include #include // std::size_t #include #include namespace cbn { namespace detail { template constexpr auto precompute_m_prime_nontight(std::integer_sequence, std::index_sequence) { constexpr auto D = sizeof...(Divisor); constexpr big_int d{Divisor...}; constexpr auto ell = bit_length(d - big_int<1, T>{1}); // TODO: should this indeed be d-1 ??? constexpr auto w = std::numeric_limits::digits; constexpr auto limb_shifts = ell / w; constexpr auto bit_shifts = ell % w; constexpr auto pow2ell = place_at(static_cast(1) << bit_shifts, limb_shifts); constexpr auto pow2N = unary_encoding(); constexpr auto divrem = div(mul(pow2N, subtract(pow2ell, d)), d); constexpr auto mp = to_length(add(divrem.quotient, big_int<1, T>{static_cast(1)})); return std::integer_sequence{}; } template constexpr auto precompute_m_prime(std::integer_sequence) { auto m = precompute_m_prime_nontight(std::integer_sequence{}, std::make_index_sequence{}); return take_first(m, std::make_index_sequence{}); } } // end of detail namespace template CBN_ALWAYS_INLINE constexpr auto quotient(big_int n, std::integer_sequence) { // Integer division with compile-time divisor // as described in "Division by Invariant Integers using Multiplication", // by Granlund and Montgomery, 1994 // https://gmplib.org/~tege/divcnst-pldi94.pdf // // inputs: // n divident // Divisor... compile-time divisor // using detail::to_length; using detail::skip; constexpr big_int d{Divisor...}; if constexpr (sizeof...(Divisor) > N) return big_int<1,T>{static_cast(0)}; else if constexpr (d == big_int<1,T>{static_cast(1)}) return n; else { // Compile-time precomputation of m_prime constexpr auto ell = detail::bit_length(d - big_int<1, T>{1}); constexpr auto w = std::numeric_limits::digits; constexpr auto m_prime = to_big_int(detail::precompute_m_prime(std::integer_sequence{})); // end of pre-computation // Perform the division auto t1 = skip(mul(m_prime, n)); auto q = shift_right( skip<(ell - 1) / w>(add(t1, shift_right(subtract_ignore_carry(n, to_length(t1)), 1))), (ell - 1) % w); // n >= t1 return to_length(q); } } template CBN_ALWAYS_INLINE constexpr auto mod(big_int n, std::integer_sequence) // Constant-time modulo operation with a fixed modulus { auto d = quotient(n, std::integer_sequence{}); constexpr auto M = sizeof...(Modulus); return detail::to_length(subtract_ignore_carry(n, partial_mul(big_int{Modulus...}, d))); } template CBN_ALWAYS_INLINE constexpr DivisionResult, big_int> div(big_int n, std::integer_sequence) { auto quot = quotient(n, std::integer_sequence{}); constexpr auto M = sizeof...(Modulus); auto rem = detail::to_length(subtract_ignore_carry( n, partial_mul(big_int{Modulus...}, quot))); return {quot, rem}; } } // end of cbn namespace #endif