На самом деле, я только что заметил несколько простых ускорений в вашем коде.Итак, я упомяну об этом, прежде чем приступить к быстрому алгоритму:
- Используйте битовое поле вместо массива символов.Вы можете сохранить в памяти коэффициент 8.
- Ваш внешний цикл работает над всеми целыми числами.Не только простые числа.После каждой итерации начинайте с первого числа, которое еще не вычеркнуто.(это число будет простым)
Я предлагаю это, потому что вы упомянули, что это займет 70 минут.на (довольно мощной) машине для запуска N = 10,000,000
.Это выглядело неправильно, так как моя собственная тривиальная реализация может выполнить N = 2^32
менее чем за 20 секунд на ноутбуке - однопоточное, без оптимизации на уровне источника.Тогда я заметил, что вы пропустили несколько основных оптимизаций.
Вот эффективное решение.Но для этого нужно проделать определенную работу.
Ключ в том, чтобы понять, что сите Эратосфена нужно только подняться до sqrt (N) вашего целевого размера.Другими словами, вам нужно только запустить сито на всех простых числах до sqrt (N), прежде чем вы закончите.
Таким образом, хитрость заключается в том, чтобы сначала запустить алгоритм на sqrt (N).Затем выведите все простые числа в плотную структуру данных.Предварительно вычисляя все необходимые простые числа, вы нарушаете зависимость от внешнего цикла.
Теперь для остальных чисел из sqrt (N) - N вы можете вычеркнуть все числа, которые делятсялюбым простым числом в вашей предварительно вычисленной таблице.Обратите внимание, что это не зависит от всех остальных чисел.Таким образом, алгоритм теперь смущающе параллелен.
Чтобы быть эффективным, это должно быть сделано с использованием "мини" сит на блоках, которые помещаются в кэш.Чтобы быть еще более эффективным, вы должны вычислить и кэшировать взаимные значения всех простых чисел в таблице.Это поможет вам эффективно найти «начальные смещения» каждого простого числа при заполнении каждого «мини-сита».
Начальный шаг запуска алгоритма, последовательного для sqrt (N), будет очень быстрым, так как онтолько sqrt (N).Остальная часть работы полностью распараллеливается.
В полностью общем случае этот алгоритм может быть применен рекурсивно к начальному сите, но это, как правило, излишне.