А можете эту мысль подробнее развернуть? Это какая-то вариация решета Причарда?
Возможно и Причарда, не уверен.
Просто наблюдение: среди 6 чисел подряд начиная с любого кратного 6 простыми могут оказаться лишь 2 (+1,+5), а среди 30 чисел подряд начиная с любого кратного 30 простыми могут быть лишь указанные 8 штук (кроме первых 5 натуральных, их обработать отдельно, ровно как и простое 2 для варианта с только нечётными). Это тривиально доказывается проверкой делимости остальных на 2,3,5. Повезло что их ровно 8 штук - укладываются точно в байт. Значит каждый байт может содержать флаги простоты всех 30 чисел начиная с любого кратного 30. Т.е. коэффициент сжатия 30/8=3.75.
Почти как с нечётными, только не по модулю 2, а по модулю 30.
По модулю 6 тоже можно, но нужно хранить пары битов для каждых 6 натуральных чисел, т.е. коэффициент сжатия 6/2=3 вместо 2/1=2 для только нечётных. Но с парами битов работать неудобно.
Можно и ещё больше модуль взять, например 7#=210, тогда вместо 8*7=56 чисел простыми могут быть лишь 48, остальные будут кратными 7. Но 48 бит неудобно хранить. А выигрыш в размере всего лишь 4.375 вместо 3.75.
Ну да, решето Причарда примерно так и работает. Я целый день убил на прошлой неделе, чтобы в нем разобраться, и в итоге пришел к выводу, что не очень-то оно мне и нужно. Там строится "колесо" из чисел, которое как бы "прокатывается" по числовой оси и отмечает простые числа. Потом на основе результата строится следующее колесо, и так далее. Первое колесо имеет размер 2 и состоит из числа 1, второе колесо - длины 6 и числа 1 и 5, третье - длины 30 и практически ваши 1, 5, 7, 11, 13, 17, 19, 23, 25, 29. Каждое новое колесо "открывает" новое простое число, а длина колеса - это примориал последнего найденного числа.
Ну и от умножений и делений можно отказаться, обойтись только сложениями/вычитаниями.
А у меня вообще почти нет всех четырех операций - только несколько вспомогательных. Так как у меня закодированы нечетные числа, я применяю следующий алгоритм: беру битовый массив, где одни нули. Единицами помечаю составные числа. Сначала у меня есть одно простое -

. Делаю маску - три байта:
10010010
00100100
01001001Последовательно применяю эту маску к массиву чисел. Первый байт маски к первому числу, второй - ко второму, третий - к третьему, потом опять первый байт маски - к четвертому и так до конца по кругу. "Применение маски" - это логическое или:
Код:
numbers[i] = numbers[i] | mask[j]
А так как у меня (как и у всех в общем) 64-битный процессор, то я использую 64-битные числа и маски. И одно применение маски позволяет мне пометить сразу несколько десятков чисел, кратных трем. Количество чисел в маске равно проверяемому простому. Для простых, которые больше 64, некоторые числа в маске - нули, их можно не применять (потому что они ничего не меняют), поэтому я сделал два массива - один хранит маски, второй - смещения.
Этот код я только-только дописал, буквально пару часов назад, там еще куча багов пока, и правильный результат он не дает
Но работает быстро - в этом "масочном" режиме я проверяю числа до миллиарда уже за 2,5 секунды против 10 секунд у простого решета.
Следующий этап оптимизации, который я планировал попробовать - это делать составные маски для нескольких простых чисел сразу. Например, если сделать маску размером 105 чисел (

), то можно вместо 3 проходов для каждого простого сделать один. А плата небольшая - всего 100 байт оперативной памяти.
По поводу ускорения, почитайте про сегментированное решето, оптимизированное под размер кэша процессора, это очень существенно ускоряет работу с массивом.
Я уже немного в курсе теории, но практического опыта такой оптимизации пока нет. Чатгпт рекомендует ориентироваться на размер кэша L2, но, как я понимаю, невозможно явно указать процессору "держи этот массив в кэше". Процессор сам решает. Я планировал попробовать делать маски для своего алгоритма (выше описал) как раз такими, чтобы в L2 влезали (то есть сначала общая маска для чисел 3, 5, 7, 11, 13, 17, 19, потом для 23, 29, 31, 37, 41, потом 43, 47, 53, 59, 61, и так далее). Опять же, чатгпт говорит, идея ок, процессор будет держать эти маски в кеше. Дальше пока мои планы не идут.
Для ориентирования, одна из самых быстрых программ
primesieve, подсчитывает количество простых до миллиарда за 0.15с-0.2с и за 2с до 10млрд. Я так не умею, у меня получается лишь втрое медленнее.
Ну вот, а моя всего лишь в 10 раз отстает, еще чуть-чуть поднажму, и получу заслуженное третье место
