Да, и хотелось бы понять, как .. для паттерна длиной 24 и диаметром 100 среди последовательных 200 миллиардов чисел возможны лишь 640 вариантов кортежа
Ну давайте разберём на конкретном примере, возьмём паттерн 0,2,6,8,12, моя программа утверждает что первое число в кортеже должно быть
,
,
, т.е. при делении на 3 остаток может быть лишь 2, при делении на 5 лишь 1, а при делении на 7 остатки могут быть 3 или 4. Все остальные варианты остатка первого числа кортежа недопустимы. Запишем проверяемый кортеж как
и проверим утверждение о недопустимости:
а) если
, то
- т.е. тогда второе число делится на 3 (впрочем и четвёртое тоже);
б) если
, то
- т.е. четвёртое число делится на 5;
в) если
, то
- т.е. второе число делится на 5 (и четвёртое тоже);
г) если
, то
- т.е. третье число делится на 5;
д) если
, то
- т.е. третье число делится на 7;
е) если
, то
- т.е. пятое число делится на 7;
ж) если
, то
- т.е. второе число делится на 7;
з) если
, то
- т.е. четвёртое число делится на 7.
Плюс можно проверить что для указанных выше допустимых остатков ни одно из 5-ти чисел ни на 3, ни на 5, ни на 7 не делится.
Теперь подсчитаем сколько же чисел мы оставили из всего диапазона
чисел: половина остаётся по модулю 2, потом от неё треть по модулю 3, потом одна пятая по модулю 5, и в финале две седьмых по модулю 7, итого
- из любых последовательных 210 чисел проверять надо лишь два варианта кортежей. Чтобы самому руками не париться с китайской теоремой об остатках,
пойдём в Wolfram и заставим париться его, он выдаст наши два варианта (для второго исправить тройку на четвёрку в задании) для остатка для первого числа кортежа:
.
Итак, в любом интервале из 210 последовательных чисел выбираем лишь два, остаток от деления которых на 210 будет 11 или 101 и начиная с него проверяем на простоту лишь 5 чисел с заданными паттерном разностями. Я обычно начинаю с первого и последнего, это часто сразу отвергает кортеж.
Воспользуемся программой PARI/GP для проверки:
Код:
{
p=Set([0,2,6,8,12]);
start=round(1); stop=start+round(1e5);
pp=vecsum(p); n=#p;
v=vector(n,x,0);
print(start,"..",stop,":",p);
forprime(i=start, stop,
v=concat(v[2..n], [i]);
if((vecsum(v)==pp+n*v[1]),
if(v-vector(n,x,v[1])==p, print("n=",n,", ",v[1],": ",p););
);
);
}
1..100001:[0, 2, 6, 8, 12]
n=5, 5: [0, 2, 6, 8, 12]
n=5, 11: [0, 2, 6, 8, 12]
n=5, 101: [0, 2, 6, 8, 12]
n=5, 1481: [0, 2, 6, 8, 12]
n=5, 16061: [0, 2, 6, 8, 12]
n=5, 19421: [0, 2, 6, 8, 12]
n=5, 21011: [0, 2, 6, 8, 12]
n=5, 22271: [0, 2, 6, 8, 12]
n=5, 43781: [0, 2, 6, 8, 12]
n=5, 55331: [0, 2, 6, 8, 12]
Проверим остатки найденных чисел на 210:
,
,
,
,
,
,
. Плюс проверим почему отбросились например кортежи 221:0,2,6,8,12 (5 чисел начиная с
) и 311:0,2,6,8,12: дык 221 делится на 11 и 13, т.е. уже оно не простое; 311, 313, 317 простые, но 319 не простое, делится на 11 и 29.
Как видим всё совпадает, за исключением самого первого решения начиная с числа 5 - это да, артефакт, в начале числового ряда встречаются уникальные кортежи, не подпадающие под формулу остатков, их надо проверять отдельно, но это возможно лишь до модуля (210), дальше всё чётко.
(Оффтоп)
Разумеется в программе используется большее количество простых, например для этого паттерна добавление проверок по модулю 11 увеличивает диапазон в 11 раз, а количество допустимых кортежей растёт лишь в 6 раз, т.е. добавление ещё одного простого числа ускоряет проверку почти вдвое. Для того паттерна выше диаметром 100 программа использует проверку на все первые простые по 47 включительно, что и даёт интервал 615 квадриллионов (
), но разных остатков для первого числа в кортеже допустимо лишь чуть меньше 96 миллионов, ускорение проверки примерно в 6 миллионов раз (все 24 числа кортежа проверять на простоту не нужно, для отбрасывания кортежа обычно хватает одного-двух). Ещё два-три порядка ускорения даёт использование ассемблера и AVX2. Памяти при этом хапнула 1.5ГБ, причём вся она постоянно читается, что иногда и ограничивает скорость.