Я поднимаю некоторый базис b до степени p и беру по модулю m этого.
Давайте предположим, что b = 55170 или 55172 и m = 3043839241 (что является квадратом 55171). Linux-калькулятор bc
дает результаты (нам это нужно для контроля):
echo "p=5606;b=55171;m=b*b;((b-1)^p)%m;((b+1)^p)%m" | bc
2734550616
309288627
Теперь вычисление 55170 ^ 5606 дает несколько большее число, но, поскольку мне нужно выполнить модуляцию, я могу обойти использование BigInt, как мне показалось, из-за:
(a*b) % c == ((a%c) * (b%c))%c i.e.
(9*7) % 5 == ((9%5) * (7%5))%5 =>
63 % 5 == (4 * 2) %5 =>
3 == 8 % 5
... и a ^ d = a ^ (b + c) = a ^ b * a ^ c, поэтому я могу разделить b + c на 2, что дает для четных или нечетных ds d / 2 и d - (d / 2), поэтому для 8 ^ 5 я могу вычислить 8 ^ 2 * 8 ^ 3.
Итак, мой (неисправный) метод, который всегда отключает делитель на лету, выглядит так:
def powMod (b: Long, pot: Int, mod: Long) : Long = {
if (pot == 1) b % mod else {
val pot2 = pot/2
val pm1 = powMod (b, pot2, mod)
val pm2 = powMod (b, pot-pot2, mod)
(pm1 * pm2) % mod
}
}
и подается с некоторыми значениями
powMod (55170, 5606, 3043839241L)
res2: Long = 1885539617
powMod (55172, 5606, 3043839241L)
res4: Long = 309288627
Как мы видим, второй результат точно такой же, как приведенный выше, но первый выглядит совершенно иначе. Я делаю много таких вычислений, и они кажутся точными, пока они находятся в диапазоне Int, но я не вижу никакой ошибки. Использование BigInt также работает, но слишком медленно:
def calc2 (n: Int, pri: Long) = {
val p: BigInt = pri
val p3 = p * p
val p1 = (p-1).pow (n) % (p3)
val p2 = (p+1).pow (n) % (p3)
print ("p1: " + p1 + " p2: " + p2)
}
calc2 (5606, 55171)
p1: 2734550616 p2: 309288627
(тот же результат, что и для bc) Может кто-нибудь увидеть ошибку в powMod
?