Следуя хорошей традиции таких вопросов, как « Найти наибольшее простое число, длина, сумма и произведение которого простое» , это вариант самой большой простой задачи.
вход
Ваш код не должен принимать никаких данных.
Определение
Мы говорим, что премьер p
является , good
если p-1
имеет ровно 2
различные простые множители.
Выход
Ваш код должен выводить абсолютную разницу между последовательными хорошими простыми числами q
и, p
таким образом, |q-p|
быть как можно большей и q
наименьшим хорошим простым, большим, чем p
. Вы можете вывести любое количество хороших пар, и ваш последний результат будет принят за оценку.
пример
Последовательность первых 55 хороших простых чисел https://oeis.org/A067466 .
Гол
Ваша оценка просто |q-p|
для пары хороших простых чисел, которые вы выводите.
Языки и библиотеки
Вы можете использовать любой язык или библиотеку, которая вам нравится (которая не была предназначена для этой задачи), кроме любых библиотечных функций для тестирования простоты или факторизации целых чисел. Тем не менее, для целей скоринга я буду запускать ваш код на моей машине, поэтому, пожалуйста, предоставьте четкие инструкции о том, как запустить его в Ubuntu.
Моя машина Время будет запущено на моей машине. Это стандартная установка Ubuntu на 8-гигабайтный 8-ядерный процессор AMD FX-8350. Это также означает, что мне нужно иметь возможность запускать ваш код.
Детали
- Я убью твой код через 2 минуты, если до этого ему не хватит памяти. Поэтому следует обязательно вывести что-то перед обрезкой.
- Вы не можете использовать какой-либо внешний источник простых чисел.
- Вы можете использовать вероятностные методы первичного тестирования, хотя Mego сказал мне, что с хорошими таблицами Миллер-Рабин может детерминистически тестировать до 341,550,071,728,321 (или даже выше). Смотрите также http://miller-rabin.appspot.com/ .
Лучшие записи, которые проверяют все целые числа из 1
- 756 котом в го
- 756 от El'endia Starman в Python
- 1932 Аднаном в C # (используя моно 3.2.8)
- 2640 по йети в Python (с использованием Pypy 4.01)
- 2754 Рето Коради в C ++
- 3486 Питер Тейлор на Яве
- 3900 примо в RPython (используя pypy 4.01)
- 4176 кодером на Яве
Лучшие записи, которые могут пропустить большое количество целых чисел, чтобы найти большой пробел
- 14226 Рето Коради в C ++
- 22596 по primo в RPython (используя pypy 4.01). Запись достигнута через 5 секунд!
источник
Ответы:
RPython (PyPy 4.0.1), 4032
RPython - это ограниченное подмножество Python, которое можно преобразовать в C и затем скомпилировать с помощью RPython Toolchain. Его выраженная цель - помочь в создании языковых переводчиков, но его также можно использовать для компиляции простых программ.
Для компиляции загрузите текущий исходный код PyPy (PyPy 4.0.1) и выполните следующее:
Полученный исполняемый файл будет назван
good-primes-c
или похож в текущем рабочем каталоге.Замечания по реализации
Генератор простых чисел
primes
- это неограниченное сито Эратосфена, которое использует колесо, чтобы избежать любых кратных 2 , 3 , 5 или 7 . Он также вызывает себя рекурсивно для генерации следующего значения, которое будет использоваться для маркировки. Я вполне доволен этим генератором. Профилирование линий показывает, что две самые медленные линии:поэтому я не думаю, что есть много возможностей для улучшения, кроме, возможно, использования большего колеса.
Для проверки «добродетели» сначала из n-1 удаляются все факторы из двух , используя хитроумный хак, чтобы найти наибольшую степень двух, которая является делителем
(n-1 & 1-n)
. Поскольку p-1 обязательно даже для любого простого числа p> 2 , отсюда следует, что 2 должно быть одним из различных простых факторов. То, что осталось, отправляетсяis_prime_power
функции, которая делает то, что подразумевает ее имя. Проверка, является ли значение простой степенью, «почти свободна», так как это делается одновременно с проверкой первичности, с не более чем O (log p n) операциями, где p - наименьший простой коэффициент n, Деление проб может показаться немного наивным, но по моим тестам это самый быстрый метод для значений менее 2 32, Я немного экономлю, повторно используя колесо из сита. Особенно:перебирая колесо длиной 48,
p*p < n
проверка будет пропущена тысячи раз по низкой низкой цене, не превышающей 48 дополнительных операций по модулю. Это также пропускает более 77% всех кандидатов, а не 50%, принимая только шансы.Последние несколько выходов:
Код также является допустимым Python и должен достигать 3588 ~ 3900 при запуске с последним интерпретатором PyPy.
RPython (PyPy 4.0.1), 22596
Это представление немного отличается от других, опубликованных до сих пор, в том, что оно не проверяет все хорошие простые числа, но вместо этого делает относительно большие скачки. Одним из недостатков этого является то, что сита не могут быть использованы [Я исправлен?] , Поэтому нужно полностью полагаться на тестирование на простоту, которое на практике немного медленнее. Существует также радостная среда между скоростью роста и количеством проверяемых значений каждый раз. Меньшие значения гораздо быстрее проверяются, но большие значения с большей вероятностью будут иметь большие пропуски.
Чтобы успокоить математических богов, я решил следовать последовательности, подобной Фибоначчи, имея следующую отправную точку как сумму двух предыдущих. Если после проверки 10 пар новые записи не найдены, скрипт переходит к следующей.
Последние несколько выходов:
При компиляции используются 64-битные целые числа, хотя в некоторых местах предполагается, что два целых числа могут быть добавлены без переполнения, поэтому на практике можно использовать только 63. По достижении 62 значащих битов текущее значение уменьшается вдвое, чтобы избежать переполнения в вычислениях. В результате сценарий перебирает значения в диапазоне 2 60 - 2 62 . Непревзойденная точность целых чисел также делает скрипт быстрее при интерпретации.
Следующий скрипт PARI / GP может использоваться для подтверждения этого результата:
источник
Вероятно, 4032, смешанное сито Аткина-Бернштейна и "детерминированный" Миллер-Рабин
Факторизация колес и хорошие простые числа
Совершенно очевидно, что за исключением 2, 3 и 5, каждое простое число взаимно простое с 2 * 3 * 5 = 60. Существует 16 классов эквивалентности по модулю 60, которые взаимно просты с 60, поэтому любой тест на простоту должен проверять только те 16 случаев.
Однако, когда мы ищем «хорошие» простые числа, мы можем еще больше развести стадо. Если
gcd(x, 60) = 1
мы обнаружим, что в большинстве случаевgcd(x-1, 60)
это либо 6, либо 10. Существует 6 значений,x
для которых оно равно 2:Поэтому мы можем заранее вычислить «хорошие» простые числа формы
2^a 3^b + 1
и2^a 5^b + 1
объединить их в результат простого генератора, который рассматривает только 10% чисел как даже потенциальные простые числа.Замечания по реализации
Так как у меня уже была Java-реализация сита Аткина-Бернштейна, и он уже использует колесо в качестве ключевого компонента, казалось естественным убрать ненужные спицы и адаптировать код. Первоначально я пытался использовать архитектуру производителя-потребителя, чтобы использовать 8 ядер, но управление памятью было слишком запутанным.
Чтобы проверить, является ли простое число «хорошим» простым, я использую «детерминированный» тест Миллера-Рабина (который на самом деле означает тест Миллера-Рабина, который кто-то другой предварительно проверил по списку, сгенерированному детерминистически). Это, конечно, можно переписать, чтобы использовать также Atkin-Bernstein, с некоторым кэшированием для охвата диапазонов, соответствующих sqrt, cbrt и т. Д., Но я не уверен, будет ли это улучшением (потому что это будет тестирование множества чисел, которые Мне не нужно проверять), так что это эксперимент на другой день.
На моем довольно старом компьютере это работает
ровно через 2 минуты, а затем
в 3:10, 3:20 и 3:30 соответственно.
Сохранить как
PPCG65876.java
, скомпилировать какjavac PPCG65876.java
и запустить какjava -Xmx1G PPCG65876
.источник
isGood
проверку.C ++, 2754 (все значения, тест на грубость)
Это грубая сила, но это начало, прежде чем наши математики-резиденты могли бы начать работать с чем-то более эффективным.
Я могу добавить еще несколько объяснений, если это необходимо, но это, вероятно, очень очевидно из кода. Так как, если
p
простое число отлично от 2, мы знаем, чтоp - 1
оно четное, и один из двух факторов всегда равен 2. Поэтому мы перечисляем простые числа, уменьшаемp - 1
на все факторы 2 и проверяем, что оставшееся значение является либо простым, либо что все его факторы одинаковы.Код:
Программа печатает разницу, а также соответствующие два простых числа каждый раз, когда обнаруживается новая максимальная разница. Пример выходных данных из тестового прогона на моей машине, где сообщенное значение 2754 найдено примерно через 1:20 минут:
источник
C ++, 14226 (только высокие значения, тест Миллера-Рабина)
Размещать это отдельно, потому что оно полностью отличается от моего первоначального решения, и я не хотел полностью заменять пост, получивший множество голосов.
Спасибо @primo за указание на проблему с оригинальной версией. В тесте простых чисел произошло переполнение больших чисел.
Это использует некоторые идеи, которые были получены в ходе эволюции других решений. Основные наблюдения:
Исходя из этого, используемый здесь метод довольно прост:
Полученные результаты:
Код:
источник
PyPy-2.4.0
Python-2
x
ФайлS...Эпизод: «Смотри, мама! Ни одного подразделения!»
;-)
Я протестировал его на Debian8 с PyPy-2.4.0, и Python2 начал как:
Если оперативной памяти достаточно,
del L[n]
строка может быть удалена.Основной генератор простых чисел таков:
Он в основном делает именно то, что делает сито Эратосфена, но в другом порядке.
L
это словарь, но может рассматриваться как список (лента) списков чисел. Несуществующие ячейкиL[n]
интерпретируются какn
не имеющие известных делителей до сих пор.while
Цикл делает простое или не простое decission на каждом витке дляL[n]
.Если
L[n]
существует (так же, какn in L
),P = L[n]
это список различных простых делителейn
. Такn
что не премьер.Если
L[n]
не существует, не найден простой делитель. Такn
что тогда должно быть главное,P = [n]
чтобы быть известным делителем.Теперь
P
список известных простых делителей для обоих случаев.for p in P
Цикл перемещает каждую запись изP
вперед на расстояние его значение на ленте чисел.Вот как делители прыгают на ленте, и это причина, почему эти числа должны быть простыми. Новые числа попадают на ленту только по
else
вышеприведенному решению, и это числа без известных делителей, кроме самих себя. Непримеры никогда не попадают в эти спискиL[n]
.Простые числа, попадающие в список, различны, потому что каждое число
n
просматривается только один раз и добавляется только как делитель (если не простое число :)0
или (если простое число :)1
. Известные простые делители только будут двигаться вперед, но никогда не будут дублироваться. Так чтоL[n]
всегда будет иметь различные простые делители или будет пустым.Вернемся к верхней программе для пробелов хороших простых чисел:
... сохраняет главные делители
n
в тех случаях,B
когдаn
известно, что они не простые.Если
n
признается простым,B
содержит список простых делителей предыдущего прохода цикла, глядя наn-1
:... значит
len(B) == 2
средствоn - 1
имеет два разных простых делителя.g
просто вспоминает последнее увиденное хорошее прайм перед новым,M
это длина предыдущего максимального хорошего простого промежутка иm
длина вновь найденного промежутка.Счастливый конец.
источник
C #, вероятно, 1932
Я узнал, что чем быстрее ваш алгоритм поиска простых чисел, тем лучше ваш счет. Я также почти уверен, что мой алгоритм не самый оптимальный метод для простого поиска.
источник
Питон 3, 546
... через две минуты на моей машине, которая, я думаю, значительно менее мощная, чем ваша.
Я, вероятно, мог бы сделать это более эффективным путем оптимизации для
x=2
случая, но да. Достаточно хорошо. :Писточник
p: 2, q: 3, |q-p|: 1
для меня.Иди, наверное 756
Стыдно! Я такой новичок, что только наивно использовал какой-то старый код и ожидал, что он будет работать и будет быстрым! Если бы я переопределил это и фактически построил это вокруг хороших простых чисел, это было бы намного быстрее, но увы, я учусь. (Вероятно, завтра я отвечу снова с полностью перестроенным решением, созданным специально.)
Очевидно, использует параллелизм.
источник
Ява, 4224 (99,29 с)
Сильно настроенное сито из эратосфена с преимуществом BitSet
Требуемое время зависит от максимального лимита простых чисел, которые будут рассчитываться.
Для
источник
Питон 3, 1464
С помощью Лембика , чья идея состояла в том, чтобы просто проверить первые два хороших простых числа после степени двойки и, когда они найдены, немедленно перейти к следующей степени двух. Если кто-то может использовать это как трамплин, не стесняйтесь. Часть моих результатов ниже после запуска этого в режиме ожидания. Код следует.
Кредит на Примо когда я взял их список небольших простых чисел для этого кода.
Редактировать: я отредактировал код, чтобы он соответствовал фактическим спецификациям задачи (два разных простых делителя не совсем два различных простых делителей), и я внедрено не переходить к следующему двойки , пока хорошо не воспламеняет программа обнаружила есть разрыв больше, чем у двух последних простых чисел, которые он нашел. Я также должен отдать должное Питеру Тейлору , поскольку я использовал его идею о том, что хорошими простыми числами могут быть только несколько значений мод 60.
Опять же, я запустил это на медленном компьютере в IDLE, поэтому результаты могут быть быстрее в чем-то вроде PyPy, но я не смог проверить.
Образец моих результатов (p, q, qp, time):
Мой код:
источник
j
,4
а не2
? И вы , кажется, отказаться безусловно , еслиj-1
это не простое число степеней двойки, где вы должны быть тестирование , является ли это прайм власть раз превышает степень двойки.Go: все целые числа: 5112
good.go
:Выход:
Для сравнения: PeterSO Max 5112 в 41,04 с против Coder Max 4176 в 51,97 с.
Кодер: max | qp | 4176 кв 1964330609 р 1964326433
Выход:
источник