Здравствуйте. Не так давно, обнаружил (возможно это уже известный, но не для меня) паттерн в распределении простых чисел.
Воспользуемся формулировкой теста простоты Агравала-Каяла-Саксены:
где
- множество простых чисел.
Это записано не совсем корректно (оригинальная формула недоступна для моего понимания, поэтому воспользовался тем, что узнал на канале Numberphile в переводе Mad Astronomer'а), но так я хотел сказать: если каждый биномиальный коэффициент (за исключением двух единиц) разложения
делится на
, то
- простое.
Вычисление
-ой строки треугольника Паскаля (содержащей необходимые биномиальные коэффициенты) обладает алгоритмической сложностью порядка
операций сложения или
операций нахождения факториала и их отношений. Факториалы можно вычислять быстрее если использовать дерево умножений. Можно еще быстрее, определяя сколько в факториале простых множителей используя деление аргумента на простые числа меньшие либо равные аргументу факториала, записывать в память целое от такого деления как степени простых чисел. Если степень какого-либо простого в факториале числителя равна сумме степеней того же числа в факториалах знаменателя то, этот коэффициент не поделится на
, так как все степени этого числа были исчерпаны при делении факториалов, а не постое
содержит степень именно такого простого числа. На мой взгляд, это как-то связано с теоремой Люка о делимости биномиальных коэффициентов на простые числа, описание в Википедии оказалось для меня слишком сложным. В последнем случае нужно знать простое ли
- следует ли добавить 1 в новый элемент списка степеней, или добавить некотрые числа к степеням уже известных простых чисел. Сложность порядка
операций деления и сложения\вычитания.
Это очень медленно! А битовая сложность еще больше.
Нельзя ли как-то добыть информацию о делимости каждого биномиального коэффициента на
без его вычисления? Предположим, что в некоторых, особо удачных случаях можно. Но догадка оказалась неверна, однако приводит к неплохим результатам. В чем суть, сумма чисел в
-ой строке триугольника Паскаля равна
. отбросим единицы как заведомо не делимые на
. Если такую сумму можно равномерно распределить между
слогаемым (всего коэффициентов в строке
, убрали две единицы, стало
слагаемых), и она делится на
, то
- простое. Сформулируем критерий:
Но, возможна ситуация, когда
- составное и коэффициенты
-ой строки не только в сумме делятся на
, но и при распределении на равные слогаемые, так же делятся на
. Если сумма делится, к примеру на 7 , но отдельные слагаемые - нет и количество слагаемых при этом уменьшается:
- не строка из треугольника Паскаля, просто иллюстрация.
Кажется, что можно отсеять такие строки, если распределить по слагаемым сумму строки равномерно, т.е. взять среднее значение.
В том случае, если некоторые коэффициенты не делятся на
, существование целочисленного среднего значения, также не дает нам точной информации, о делимости каждого коэффициента на
. Пример:
Кажется, что количество слагаемых уменьшилось и такая сумма не распределится на 4 одинаковых слагаемых (т.е. не поделится на 4 - число слагаемых), но не тут-то было:
Но к моему удивлению такая ситуация для строк триугольника Паскаля весьма редка, при
ложно-положительные результаты отсутствуют. Ложно-отрицательных результатов много. Нашел контрпример
- явно принадлежит множеству чисел Мерсена исходя из его вида, и такого числа нет в списке всех известных чисел Мерсена (в этом списке нет пропусков), следовательно
- не простое. Так же, замечено, что общий вид критерия поиска
чуть менее эффективен, но число ложно-положительных результатов для
сопоставимых порядков быстро убывает с ростом порядка величины проверяемых чисел. К примеру для
- 14-ое возвращенное значение функции (код приведу ниже) составное, а следующее составное не 28-ое как может показатся, а 43-е. Исследовал все
- возвращаемые значения совпадают с множеством простых чисел Мерсена, только в начале. Наибольшее совпадение -
- 9-ое простое число Мерсена.
def Agrawal_Kayal_Saxena_primality_test(natural_number):
"""There is primality test based on AKS primality test. For all "n", if
(x + 1) ** n - (x ** n - 1) is divisible by "n", then "n" is prime. But it's
so slow working.
I've made a hypotesis:
(1) {n for n in range(N) if ((2 ** n) % n == 2) and
((2 ** n) % (n - 1) == 2)
}.issubset(P) == True,
where N - set of natural numbers; P - set of prime numbers, "%" - module
operator.
There have a lot of false negative and a bit of false positive returns.
For example n = 2 ** 43 - 1 is not prime, but test return True. How did I
find this minimal counterexample where "n" is very large? I used the fast
implementation of 2 ** Mn by module Mn, where Mn - is n-th Mersene number.
(2) 2 ** Mn % Mn == 2 ** (2 ** n - 1) % (2 ** n - 1) ==
2 ** ((2 ** n - 1) % n) == 2 ** (Mn % n)
By the diffinition of (2) we can make fast implementation of 2 ** Mn %
(Mn - k), where k in N.
(3) 2 ** Mn % (Mn - k) == 2 ** (2 ** n - 1) % (2 ** n - 1 - k) ==
2 ** ((2 ** n - 1) % (n - k)) == 2 ** (Mn % (n - k))
For example:
2 ** M19 % (M19 - 1) == 2 ** ((2 ** 19 - 1) % (19 - 1)) ==
== 2 ** ((2 ** 19 - 1) % 18) == 2
If we divide 2 ** (2 ** n - 1) by 2 ** n we got a 2 ** ((2 ** n - 1) - n) of
1-s, wich compliting every single 2 ** n - 1. (included in the decomposition
of 2 ** Mn to an addendums) to 2 ** n. Divide the resulting number by 2 ** n
and so on, until possible it to devide. When number could't to divided, then
it's an remainder of 2 ** (2 ** n - 1) by module of (2 ** n - 1),
i.e. 2 ** Mn % Mn.
Q.E.D.
Suppose, bit lengths of numbers Mersene numbers b1 and b2:
b1 = math.log2(2 ** (2 ** n - 1) - 1),
b2 = math.log2(2 ** (2 ** n - 1) - 1).
Then be able to explain why the FMMM algorithmis faster then all other. It's
faster then anythin else algoritm for powering by module, because this
imlementation reduce complexity of problem to
O(math.log2(b1) * math.log2(log(b1))) from O(b1 * math.log2(b1))
for fast powering by module. Logarithmic complexity simplification!
"""
def AKS_rowsum(row_index):
"""Sum an addendums in a n-th row of Pascal's Triangle (except are 0-th
and n-th of addendums).
It is a special representation of core condition of
Agrawal-Kayal-Saxena primality test.
"""
return (1 << row_index) - 2
# Is equivalen of 2 ** power - 2 in terms bit-magic. I used bit-magic
# because that is faster than naive method.
def AKS_extension(applicant):
specrep = AKS_rowsum(applicant)
divisibilty = specrep % applicant
distribytility = specrep % (applicant - 1)
# A sum is able distribyted on equal summands in type like "a * c",
# where "a" is applicant to a prime number; c - is some multiplier.
# (applicant - 1) is quantity of summands in special representation
# of AKS core condition.
return False if divisibilty or distribytility else True
return AKS_extension(natural_number)
Для
критерию соответствуют 33 простых числа:
7, 19, 43, 127, 163, 379, 487, 883, 1459, 2647, 3079, 3943, 5419, 9199, 11827, 14407, 16759, 18523, 24967, 26407, 37339, 39367, 42463, 71443, 77659, 95923, 99079, 113779, 117307, 143263, 174763, 175447, 184843
Почему это работает? Почему так мало контрпримеров?