Имея две операции по модулю, есть избыточность, но одна из них решает именно эту проблему с числами, взрывающимися в размере, если алгоритм не завершается очень рано (что он делает для 121).
Это работает, потому что можно использовать любой многочлен?
Это немного более тонко, и бросание операций по модулю в микс на самом деле не случай "любого полинома". Ключ в том, что алгоритм ищет два значения в некоторой последовательности x[i]
и x[j]
с i != j
, так что abs(x[i] - x[j])
кратно p
(где N = pq
и ни p
, ни q
равны 1), или, другими словами, abs(x[i] - x[j]) mod p = 0
или x[i] ≡ x[j] mod p
. В этот момент цикл был найден в последовательности при просмотре по модулю p
, и, что важно, если x[i] != x[j]
, тогда их разность ненулевое кратное p
, что дает шанс извлечь коэффициент из N
. По крайней мере, если их разность не кратна N
(в этом случае результатом из GCD будет сам N
, и коэффициент не будет получен).
Таким образом, если смотреть чисто на математику, то шаг по модулю N
теоретически не нужен, а по циклу по модулю p
происходит без такой «помощи». Но это возможно , N = pq
, поэтому, если мы уменьшаем последовательность по модулю N
, то ее свойства по модулю p
не нарушаются и алгоритм все еще работает. Более того, уменьшение по модулю N
очень важно практически, потому что оно предотвращает становление непрактично больших чисел, что в противном случае не только замедлит алгоритм, но и в конечном итоге приведет к сбою на реальном (конечном размере) оборудовании.
Это много теоретического обоснования, реализация очень проста,
mpz_class polynomial (mpz_class x, mpz_class num)
{
return ((x * x) + 1) % num;
}