Это лучший алгоритм, который я мог придумать.
def get_primes(n):
numbers = set(range(n, 1, -1))
primes = []
while numbers:
p = numbers.pop()
primes.append(p)
numbers.difference_update(set(range(p*2, n+1, p)))
return primes
>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import get_primes').timeit(1)
1.1499958793645562
Можно ли сделать это еще быстрее?
У этого кода есть недостаток: поскольку numbers
это неупорядоченный набор, нет гарантии, что numbers.pop()
он удалит наименьшее число из набора. Тем не менее, это работает (по крайней мере для меня) для некоторых входных чисел:
>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True
python
math
optimization
primes
jbochi
источник
источник
import antigravity
. Разве нет ничего подобногоrequire 'prime'; Prime.take(10)
(Руби)?Ответы:
Предупреждение:
timeit
результаты могут отличаться из-за различий в оборудовании или версии Python.Ниже приведен скрипт, который сравнивает ряд реализаций:
Большое спасибо Стефану за то, что он привлек мое внимание к sieve_wheel_30. Заслуга Роберт Уильям Хэнкса для primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1 и rwh_primes2.
Из простых методов Python, протестированных с psyco , для n = 1000000, rwh_primes1 был самым быстрым из протестированных.
Из простых методов Python, протестированных без psyco , для n = 1000000, rwh_primes2 был самым быстрым.
Из всех протестированных методов, допускающих numpy , для n = 1000000, primesfrom2to был самым быстрым из протестированных.
Время измерялось с помощью команды:
с
{method}
заменой каждого из имен методов.primes.py:
Выполнение сценариев проверяет, что все реализации дают одинаковый результат.
источник
gmpy
- у него довольно хорошая поддержка простых чисел с помощьюnext_prime
метода егоmpz
типа.Быстрее и больше памяти чистый код Python:
или начиная с половины сита
Быстрее и больше памяти кода:
более быстрое изменение, начинающееся с трети сита:
(Трудно кодируемая) версия чистого кода выше для Python будет выглядеть так:
К сожалению, pure-python не использует более простой и быстрый способ выполнения присваивания, и вызов
len()
внутри цикла, например,[False]*len(sieve[((k*k)//3)::2*k])
слишком медленный. Поэтому мне пришлось импровизировать, чтобы исправить ввод (и избегать больше математики) и сделать некоторую экстремальную (и болезненную) математику.Лично я думаю, что это позор, что numpy (который так широко используется) не является частью стандартной библиотеки Python, и что улучшения в синтаксисе и скорости, кажется, полностью игнорируются разработчиками Python.
источник
bitarray
- как здесь используется (для простейшего простого решета; здесь нет соперника в гонке!) stackoverflow.com/questions/31120986/…primesfrom2to()
методе, должно ли деление быть внутри скобок?Там довольно аккуратный пример из Python Cookbook здесь - самый быстрый вариант , предложенный по этому URL является:
так что дало бы
Измеряя в приглашении оболочки (как я предпочитаю делать) с этим кодом в pri.py, я наблюдаю:
Похоже, что решение Cookbook более чем в два раза быстрее.
источник
Используя Сито Сундарама , я думаю, что побил рекорд чистого Python:
Comparasion:
источник
None
вместо оригинальной функции работает, и это даже быстрее, чемzero.__sub__
sundaram3(9)
он вернется[2, 3, 5, 7, 9]
? Это , кажется, делает это с многочисленным - возможно , все - нечетными числами (даже если они не являются простыми)Алгоритм быстрый, но у него есть серьезный недостаток:
Вы предполагаете,
numbers.pop()
что вернет наименьшее число в наборе, но это совсем не гарантировано. Наборы неупорядочены,pop()
удаляют и возвращают произвольный элемент, поэтому его нельзя использовать для выбора следующего простого числа из оставшихся чисел.источник
Для действительно быстрого решения с достаточно большим N было бы загрузить предварительно вычисленный список простых чисел , сохранить его как кортеж и сделать что-то вроде:
Если бы
N > primes[-1]
только тогда вычислите больше простых чисел и сохраните новый список в своем коде, так что в следующий раз он будет таким же быстрым.Всегда мыслить нестандартно.
источник
Если вы не хотите изобретать велосипед, вы можете установить библиотеку символических математических файлов sympy (да, она совместима с Python 3)
И использовать функцию простого ряда
источник
Если вы принимаете itertools, но не NumPy, вот адаптация rwh_primes2 для Python 3, которая работает примерно в два раза быстрее на моей машине. Единственным существенным изменением является использование байтового массива вместо списка для логического значения и использование сжатия вместо понимания списка для построения окончательного списка. (Я бы добавил это как комментарий, как moarningsun, если бы смог.)
Сравнения:
а также
источник
Поучительно написать свой собственный основной код поиска, но также полезно иметь быструю надежную библиотеку под рукой. Я написал обертку вокруг primesieve библиотеки C ++ , назвал ее primesieve-python
Попробуй это
pip install primesieve
Мне было бы любопытно увидеть скорость по сравнению.
источник
count_primes
функция намного быстрее, чемgenerate_primes
Вот две обновленные (чистый Python 3.6) версии одной из самых быстрых функций,
источник
Детерминистическая реализация критерия примитивности Миллера-Рабина в предположении, что N <9,080,191
Согласно статье в Википедии ( http://en.wikipedia.org/wiki/Miller–Rabin_primality_test ) тестирование N <9,080,191 для a = 2,3,37, и 73 достаточно, чтобы решить, является ли N составным или нет.
И я адаптировал исходный код из вероятностной реализации оригинального теста Миллера-Рабина, найденного здесь: http://en.literateprograms.org/Miller-Rabin_primality_test_(Python)
источник
Если у вас есть контроль над N, самый быстрый способ перечислить все простые числа - это предварительно вычислить их. Шутки в сторону. Предварительные вычисления - это способ игнорирования оптимизации.
источник
Вот код, который я обычно использую для генерации простых чисел в Python:
Он не может конкурировать с более быстрыми решениями, размещенными здесь, но, по крайней мере, это чистый питон.
Спасибо за размещение этого вопроса. Я действительно многому научился сегодня.
источник
Для самого быстрого кода, решение NumPy является лучшим. Однако по чисто академическим причинам я публикую свою версию на чистом Python, которая чуть менее чем на 50% быстрее, чем версия поваренной книги, опубликованная выше. Поскольку я делаю весь список в памяти, вам нужно достаточно места, чтобы вместить все, но, похоже, он достаточно хорошо масштабируется.
И результаты:
источник
Немного другая реализация полусита с использованием Numpy:
http://rebrained.com/?p=458
Может кто-то сравнить это с другими временами? На моей машине это выглядит довольно сравнимо с другим половинным ситом Numpy.
источник
upto=10**6
:primesfrom2to()
- 7 мс;prime6()
- 12 мс ideone.com/oDg2YЭто все написано и проверено. Таким образом, нет необходимости изобретать велосипед.
дает нам рекорд 12,2 мсек !
Если это не достаточно быстро, вы можете попробовать PyPy:
что приводит к:
Ответ с 247 голосами "за" составляет 15,9 мс для лучшего решения. Сравните это !!!
источник
Я проверил некоторые функции Unutbu , я вычислил это с числом голодных миллионов
Победителями являются функции, которые используют библиотеку NumPy,
Примечание : было бы интересно сделать тест на использование памяти :)
Образец кода
Полный код в моем репозитории github
источник
Для Python 3
источник
Самое быстрое простое сито в Pure Python :
Я оптимизировал Sieve of Eratosthenes для скорости и памяти.
эталонный тест
Вывод
источник
Впервые использую python, поэтому некоторые методы, которые я использую в этом, могут показаться немного громоздкими. Я просто преобразовал свой код C ++ в Python, и это то, что у меня есть (хотя и немного медленный в Python)
источник
Я знаю, что конкурс закрыт в течение нескольких лет. ...
Тем не менее, это мое предложение для простого сита Python, основанное на пропуске кратных 2, 3 и 5 с использованием соответствующих шагов при обработке сита вперед. Тем не менее, для N <10 ^ 9 он на самом деле медленнее, чем у @Robert William Hanks превосходных решений rwh_primes2 и rwh_primes1. Использование ситового массива ctypes.c_ushort выше 1,5 * 10 ^ 8 позволяет адаптировать его к ограничениям памяти.
10 ^ 6
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000)" 10 циклов, лучшее из 3: 46,7 мс на цикл
10 ^ 7
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (10000000)" 10 циклов, лучшее из 3: 530 мс на цикл
10 ^ 8
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (100000000)" 10 циклов, лучшее из 3: 5,55 с на цикл
10 ^ 9
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000000)" 10 циклов, лучшее из 3: 61,2 с на цикл
Вы можете скопировать приведенный ниже код в ubuntus primeSieveSpeedComp для проверки этих тестов.
источник
Вот небольшая версия Sieve of Eratosthenes, имеющая как хорошую сложность (ниже, чем сортировка массива длины n), так и векторизацию. По сравнению с @unutbu раз это так же быстро, как пакеты с 46 микросекундами, чтобы найти все простые числа меньше миллиона.
Тайминги:
источник
Я обновил большую часть кода для Python 3 и бросил его на perfplot ( мой проект), чтобы увидеть, какой из них действительно самый быстрый. Оказывается, что, по большому счету
n
,primesfrom{2,3}to
возьмите торт:Код для воспроизведения сюжета:
источник
Я предполагаю, что самый быстрый из всех способов - это жестко закодировать простые числа в вашем коде.
Так почему бы просто не написать медленный сценарий, который генерирует другой исходный файл со всеми номерами, записанными в нем, а затем импортировать этот исходный файл при запуске вашей реальной программы.
Конечно, это работает, только если вы знаете верхнюю границу N во время компиляции, но это относится к (почти) всем проблемам Эйлера проекта.
PS: Я могу ошибаться, хотя если исходный код разбирается с помощью жестко запрограммированных простых чисел, это медленнее, чем вычисление их в первую очередь, но насколько я знаю, Python запускается из скомпилированных
.pyc
файлов, поэтому чтение двоичного массива со всеми простыми числами до N должно быть кровавым быстро в этом случае.источник
Извините, что беспокою, но erat2 () имеет серьезный недостаток в алгоритме.
При поиске следующей композиции нам нужно проверить только нечетные числа. q, p оба нечетны; тогда q + p четно и не нуждается в проверке, но q + 2 * p всегда нечетно. Это исключает проверку «если даже» в цикле while и экономит около 30% времени выполнения.
Пока мы на этом: вместо элегантного метода «D.pop (q, None)» get и delete используйте «if q в D: p = D [q], del D [q]», что в два раза быстрее ! По крайней мере, на моей машине (P3-1Ghz). Поэтому я предлагаю эту реализацию этого умного алгоритма:
источник
Самый быстрый метод, который я пробовал до сих пор, основан на функции поваренной книги Python
erat2
:Смотрите этот ответ для объяснения ускорения.
источник
Я могу опоздать на вечеринку, но мне придется добавить свой код для этого. Он использует приблизительно n / 2 в пространстве, потому что нам не нужно хранить четные числа, и я также использую модуль python bitarray, дополнительно сокращая потребление памяти и позволяя вычислять все простые числа до 1 000 000 000
Это было запущено на 64-битной 2.4GHZ MAC OSX 10.8.3
источник
Со временем я собрал несколько сит с простыми числами. Самый быстрый на моем компьютере это:
источник
Я медленно отвечаю на этот вопрос, но это казалось забавным упражнением. Я использую NumPy, который может быть мошенничеством, и я сомневаюсь, что этот метод самый быстрый, но это должно быть ясно. Он фильтрует логический массив, ссылаясь только на его индексы, и извлекает простые числа из индексов всех значений True. Не требуется по модулю.
источник
ajs_primes3a(10)
->array([2, 3, 5, 7, 9])
.9
это не простое числоnumpy
решение на основе массива, которое возвращает массив. Примечание: истинная реализация Sieve of Eratosthenes не используется по модулю - упоминать об этом не нужно. Вы могли бы использоватьmat[idx*idx::idx]
вместоmat[idx*2::idx]
. Иnp.nonzero(mat)[0]
вместоnp.where(mat == True)[0]
.Вот интересный метод генерации простых чисел (но не самый эффективный) с использованием понимания списка Python:
Вы можете найти пример и некоторые пояснения прямо здесь
источник