更新时间:2023-11-30 18:47:46
首先,一些一般性建议:
First of all, some general advice:
std :: pow
与整数一起使用,因为它对浮点数进行运算并且会失去精度.std::pow
with integers, because it operates on floating-point numbers and loses precision.对于主要问题,作为一种解决方法,您可以使用此 O(log ^ 2(n))
解决方案,该解决方案应适用于最大63位的参数(因为它仅使用加法)并乘以2).请注意,如果只是以小到大的顺序遍历位,那么所有这些字符串魔术都是不必要的:
For the main question, as a workaround, you can use this O(log^2(n))
solution, which should work for arguments up to 63 bits (since it only ever uses addition and multiplication by 2). Note how all that string magic is unnecessary if you just iterate over the bits in small-to-large order:
#include <cstdint>
uint64_t modular_mul(uint64_t a, uint64_t b, uint64_t mod) {
uint64_t result = 0;
for (uint64_t current_term = a; b; b >>= 1) {
if (b & 1) {
result = (result + current_term) % mod;
}
current_term = 2 * current_term % mod;
}
return result;
}
uint64_t modular_pow(uint64_t base, uint64_t exp, uint64_t mod) {
uint64_t result = 1;
for (uint64_t current_factor = base; exp; exp >>= 1) {
if (exp & 1) {
result = modular_mul(result, current_factor, mod);
}
current_factor = modular_mul(current_factor, current_factor, mod);
}
return result;
}
此外,在gcc中,某些目标还可以使用(非标准) __ uint128_t
.(可用于将 modular_mul
替换为普通乘法)
Also, in gcc a (non-standard) __uint128_t
is available for some targets. (which can be used to replace modular_mul
with normal multiplication)