Список простых чисел до миллиона

56

Это мой первый и очень простой вопрос по гольфу, поэтому я заранее прошу прощения, если нарушил какие-либо правила сообщества.

Задача состоит в том, чтобы распечатать в порядке возрастания все простые числа менее миллиона. Формат вывода должен быть один номер на строку вывода.

Целью, как и в большинстве представлений кода для гольфа, является минимизация размера кода. Оптимизация для времени выполнения также является бонусом, но является вторичной целью.

Делан Азабани
источник
12
Это не точный дубликат, но по сути это просто тестирование на простоту, являющееся компонентом ряда существующих вопросов (например, codegolf.stackexchange.com/questions/113 , codegolf.stackexchange.com/questions/5087 , codegolf.stackexchange. ком / вопросы / 1977 ). FWIW, одно руководство, которого недостаточно соблюдают (даже те, кто должен знать лучше), - это предварительно предложить вопрос в мета-песочнице meta.codegolf.stackexchange.com/questions/423 для критики и обсуждения того, как это может быть улучшение, прежде чем люди начнут отвечать на него.
Питер Тейлор
Ах, да, меня беспокоит то, что этот вопрос слишком похож на множество вопросов, связанных с простыми числами, которые уже существуют.
Делан Азабани
2
@ GlennRanders-Pehrson Потому что 10^6еще короче;)
ɐɔıʇǝɥʇuʎs
1
Несколько лет назад я представил запись IOCCC, которая печатает простые числа с только 68 символами в C - к сожалению, она останавливается далеко за миллион, но это может быть интересно некоторым: computronium.org/ioccc.html
Computronium
1
@ ɐɔıʇǝɥʇuʎs Как насчет 1e6:-D
Титус

Ответы:

33

Математика , 17 24

Просто для сравнения:

Prime@Range@78498

Как отмечено в комментарии, я не смог указать одно простое число в строке; коррекция:

Column@Prime@Range@78498
Mr.Wizard
источник
4
Prime~Array~78498также 17 :)
chyanog
Было бы девять байтов в mthmca, если это должно было быть выпущено.
Майкл Стерн
Это нарушает условие одного простого числа на строку вывода. Префикс с Print/@и прекращение с, ;чтобы предотвратить вывод длинного списка Nullисправлений, стоимостью 8 дополнительных символов.
celtschk
@celtschk Не знаю, пропустил ли я это пять лет назад.
Мистер Волшебник
1
Ну, я определенно пропустил, что это было пять лет назад :-)
celtschk
27

Python 3, 46 байт

k=P=1
while k<1e6:P%k and print(k);P*=k*k;k+=1

К тому времени, когда цикл достигает тестирования k, он итеративно вычисляет квадрат-факториал P=(k-1)!^2. Если kпростое число, то оно не появляется в продукте 1 * 2 * ... * (k-1), поэтому это не является фактором P. Но, если он сложный, все его главные факторы меньше и поэтому в продукте. Квадрат на самом деле нужен только для того, чтобы избежать k=4ложного называния простым.

Более того, из теоремы Вильсона следует , что когда kпростое число P%kравно 1. Хотя нам нужно только, чтобы здесь он отличался от нуля, в целом полезно, чтобы P%kэто была индикаторная переменная для того, kявляется ли простое число.

XNOR
источник
23

С, 61 символ

Почти такой же, как этот (вопрос тоже почти такой же).

n=2;main(m){n<1e6&&main(m<2?printf("%d\n",n),n:n%m?m-1:n++);}
ugoren
источник
Получил SEG-FAULTпосле печати881
Manav Mn
7
@Manav, возможно, вы скомпилировали без оптимизации. Он опирается на хороший оптимизатор, который удалит рекурсию.
Угорен
4
Да добавление -O3к gccрешенной проблеме !!
Манав Мн
Этот метод безумен. Я люблю это.
Тодд Леман,
2
Я могу дать вам 57 байтовn=2;main(m){n<1e6&&main(m<2?printf("%d\n",n),n:m-++n%m);}
Альберт Реншоу
22

MATLAB (16) (12)

К сожалению, это выводится в одной строке:

primes(1000000)

но это решается простой транспонированием матрицы:

primes(1000000)'

и я могу вырезать некоторые символы, используя экспоненциальную запись (как это предлагается в комментариях):

primes(1e6)'
MBraedley
источник
5
Использование 1e6вместо 1000000помогает и здесь.
Орион
@orion Это сделало бы 11 персонажей
Аксорен
@Axoren, который не включает 'в конце
Stan Strum
20

Баш (37 символов)

seq 2 1e6|factor|sed 's/.*: //g;/ /d'

(60 символов)

seq 2 1000000|factor|sed -e 's/[0-9]*: //g' -e '/^.* .*$/ d'

на моем компьютере (2,0 ГГц процессор, 2 ГБ оперативной памяти) занимает 14 секунд.

saeedn
источник
Это может быть улучшено до: seq 2 1000000|factor|sed 's/[0-9]*: //g;/^.* .*$/ d'
Делан Азабани
Да, ты прав. Я написал свою команду sed чисто, а не в гольф: P
saeedn
3
seq 1e6|factor|awk '$0=$2*!$3'немного короче.
Деннис
1
seq, factor и sed являются внешними программами, это также может быть c pгде c символическая ссылка на cat, а p текстовый файл с простыми числами до миллиона ... вы можете сделать это с помощью встроенных команд оболочки?
технозавр
7
@technosaurus seqи factorв coreutils, так что это законно. sedтакже довольно вездесущ. coreutilsможно рассматривать как встроенный. Bash без coreutils похож на C ++ без STL.
16

J, 21 символов

1[\p:i.(_1 p:1000000)

который может быть сокращен до

1[\p:i.78498

если вы знаете, сколько простых чисел ниже 1000000.

Gareth
источник
2
Использование элементов enfile ,.вместо 1 [\\ для сохранения символа. Удалите ненужные скобки и использовать экспоненциальное обозначение: 1e6.
Омар
Придумал это: ,.i.&.(p:^:_1)1e6не короче (после применения предложений @Omar), но я нашел использование под интересно.
kaoD
10

PowerShell, 47 44 байта

Очень медленно, но самое короткое, что я мог придумать.

$p=2..1e6;$p|?{$n=$_;!($p-lt$_|?{!($n%$_)})}

PowerShell, 123 байта

Это намного быстрее; далеко не оптимальный, но хороший компромисс между эффективностью и краткостью.

 $p=2..1e6;$n=0
 while(1){$p=@($p[0..$n]|?{$_})+($p[($n+1)..($p.count-1)]|?{$_%$p[$n]});$n++;if($n-ge($p.count-1)){break}}
 $p
Rynant
источник
9

Баш, 30 байт

Так как Саидн не будет действовать по моему предложению - которое короче и быстрее, чем его подход - я решил опубликовать свой собственный ответ:

seq 1e6|factor|awk '$0=$2*!$3'

Как это устроено

seq 1e6

перечисляет все натуральные числа до 1000000.

factor

факторы их один за другим. Для первой десятки результат следующий:

1:
2: 2
3: 3
4: 2 2
5: 5
6: 2 3
7: 7
8: 2 2 2
9: 3 3
10: 2 5

В заключение,

awk '$0=$2*!$3'

изменяет всю строку ( $0) на произведение второго поля (первого простого множителя) и логического отрицания третьего поля ( 1если один простой множитель или меньше, в 0противном случае).

Это заменяет строки, соответствующие простым числам, самим числом, а все остальные строки - нулями. Так как awk печатает только истинные значения, будет напечатано только простое число.

Деннис
источник
4
awk '$0=$2*!$3'это круто круто!
йети
8

Рубин 50 41

require'mathn'
p (2..1e6).select &:prime?
Кристиан Лупаску
источник
2
Нет необходимости .to_a, так как Enumerable уже включает в себя select. Вы также можете использовать сокращенное обозначение для Symbol # to_proc, чтобы сократить его еще больше: p (2..1e6).select &:prime?(1 не простое)
Ventero
@ Ventero спасибо большое! Я не знал о Символе # to_proc. Я должен уделять больше внимания предложениям Ruby.
Кристиан Лупаску
2
Укороченная версия require'prime';p Prime.take 78498.
Hauleth
@ ŁukaszNiemier Отлично! Я думаю, что это настолько отличается, что вы можете опубликовать его как отдельный ответ.
Кристиан Лупаску
Хорошее использование хорошего старого деревенского парня по математике
DoctorHeckle
8

Баш, 37

Будет ли гольф больше, если я могу ...

Большая часть этого пытается разобрать factorнеловкий формат вывода.

seq 1e6|factor|grep -oP "(?<=: )\d+$"

Требуется 5,7 или около того секунд, чтобы завершить на моей машине.

(Так получилось, что мой пост первым перешел на вторую страницу ответов, поэтому никто его не увидит ...)

Старое решение

Это длиннее и медленнее (занимает 10 секунд).

seq 1e6|factor|egrep ':.\S+$'|grep -oE '\S+$'

источник
2
Ничего себе - я никогда не сталкивался factorпрежде, но там это прямо в coreutils!
Цифровая травма
1
Побрей одного персонажа: seq 1e6|factor|grep -oP "(?<=: )\d+$"с перл-grep взглядом назад
Digital Trauma
@DigitalTrauma как это работает
1
-Pвключает регулярные выражения в стиле Perl. (?<=: )является положительным взглядом на строку ":". В основном это говорит о том, что «:» должно идти перед тем \d+$, что соответствует , но на самом деле не является частью совпадения, поэтому -oопция просто дает нам одно совпадающее число после двоеточия, то есть просто дает числа, где есть только один фактор, то есть простое число.
Цифровая травма
@DigitalTrauma добавлено
8

Python 3.x: 66 символов

for k in range(2,10**6):
 if all(k%f for f in range(2,k)):print(k)

Более эффективное решение: 87 символов

На основе сита Эратосфена.

p=[];z=range(2,10**6)
while z:f=z[0];p+=[f];z=[k for k in z if k%f]
for k in p:print(k)
dan04
источник
1
Первый ошибочно печатает 0и 1. Вы можете исправить это, используя вместо этого range(2,10**6). Кроме того, я думаю, что ifутверждение должно быть в отдельной строке от out, forиначе вы получите ошибку.
xnor
@xnor: Исправлено.
Ден04
8

Хаскелл, 51

mapM print [n|n<-[2..10^6],all((>0).rem n)[2..n-1]]
pt2121
источник
Вы можете изменить mapM_на mapM, возвращаемое значение не будет напечатано, и это Code Golf. ;)
Догберт
почему после печати и в (> 0) есть дополнительные пробелы?
гордый haskeller
Хорошо поймал! спасибо
pt2121
Вы можете заменить 999999 на 10 ^ 6. И, пожалуйста, обновите ваш счетчик байтов - 63 не может быть правильным.
user2845840
@ user2845840 ок, спасибо. хорошая идея!
pt2121
8

APL, 15

p~,p∘.×p←1↓⍳1e6

У моего переводчика возникли проблемы с памятью, но теоретически это работает.

TwiNight
источник
Как? Можете ли вы дать описание?
Расмус Дамгаард Нильсен
Вам нужен спереди, чтобы сделать один номер в строке, и вам не нужно ,.
Адам
@RasmusDamgaardNielsen - первые целые числа. 1↓падает первый. p←назначает на р. p∘.×pделает таблицу умножения. p~удаляет из р все, что находится справа. ( ,не требуется, таблица объединяется в список.)
Адам
8

Perl, 49 байт

Регулярное выражение кунг-фу :)

for(1..1E6){(1x$_)=~/^(11+?)\1+$/ or print"$_\n"}

Безголовая версия:

for(1 .. 1_000_000) { 
    (1x$_) =~ /^(11+?)\1+$/ or print "$_\n";
}

Он даже не достиг 10% прогресса, пока я набираю этот пост!

Источник для регулярного выражения: http://montreal.pm.org/tech/neil_kandalgaonkar.shtml

Gowtham
источник
2
вдохновил меня написать версию perl6. Кроме того, 1000000может быть написано10**6
Пабо
1
Также 1000000 можно написать 1E6
моб
Обновил мой ответ. Спасибо @mob
Gowtham
Всегда был моим любимым регулярным выражением, но вы должны помнить, что когда вы доберетесь до более высоких чисел, оно не получится впечатляюще - из-за того, что оно конвертирует огромные числа в унарные. Это регулярное выражение может не работать для поиска простых чисел в сотнях тысяч и более, в зависимости от конфигурации языка (и вашего компьютера).
Codefun64,
7

Юлия, 11

primes(10^6)

Похоже, что встроенные модули получают голоса, плюс мне нужно больше слов для более длинного ответа.

GGGG
источник
7

J (15 или 9)

Я не могу поверить, что это бить Mathematica (даже если это просто один на 2 символа)

a#~1 p:a=:i.1e6

Или же:

p:i.78498
ɐɔıʇǝɥʇuʎs
источник
1
... The output format should be one number per line of output.Вот почему мой ответ начинается с 1[\ .
Гарет
6

gs2, 5 байтов

Закодировано в CP437:

∟)◄lT

1C 29толкает миллион, 11 6Cэто простые числа ниже, 54это показывать линии.

Линн
источник
5

GolfScript, 22/20 (20/19) байтов

n(6?,:|2>{(.p|%-.}do:n

За счет скорости код можно сделать на два байта короче:

n(6?,:|2>.{|%2>-}/n*

Если выходной формат, указанный в отредактированном вопросе, игнорируется (что и делают многие из существующих ответов), в быстрой версии можно сохранить два байта, а в медленной - один.

n(6?,:|2>{(.p|%-.}do
n(6?,:|2>.{|%2>-}/`

Это напечатает дополнительный LF после простых чисел для быстрой версии, и это напечатает простые числа как массив для медленной.

Как это устроено

Обе версии являются реализациями сита Эратосфена .

Быстрая версия делает следующее:

  1. Установите A = [ 2 3 4 … 999,999 ]и | = [ 0 1 2 … 999,999 ].

  2. Установите N = A[0]и распечатайте N.

  3. Соберите каждый N-й элемент из |in C. Это кратные N.

  4. Set A = A - C.

  5. Если Aне пусто, вернитесь к 2.

n(6?   # Push "\n".pop() ** 6 = 1,000,000.
,:|    # Push | = [ 0 1 2 … 999,999 ].
,2>    # Push A = [ 2 3 4 … 999,999 ].
{      #
  (    # Unshift the first element (“N”) of “A”.
  .p   # Print “N”.
  |%   # Collect every N-th element from “A” into a new array, starting with the first.
  -    # Take the set difference of “A” and the array from above.
  .    # Duplicate the set difference.
}do    # If the set difference is non-empty, repeat.
:n     # Store the empty string in “n”, so no final LF will get printed.

Медленная версия работает аналогичным образом, но вместо последовательного удаления кратных минимума «А» (который всегда является простым), она удаляет кратные всех положительных целых чисел ниже 1 000 000.

конкурентоспособность

В отсутствие каких-либо встроенных математических функций для разложения на множители или проверки на первичность все решения GolfScript будут либо очень большими, либо очень неэффективными.

Хотя это еще далеко от эффективности, я думаю, что достиг приличного соотношения скорости и размера. На момент представления этот подход, по-видимому, является самым коротким из тех, которые не используют ни одну из вышеупомянутых встроенных программ. Я говорю кажется потому что я понятия не имею, как работают некоторые ответы ...

Я протестировал все четыре представленных решения GolfScript: w0lf (пробное деление), другой мой ответ (теорема Уилсона) и два из этого ответа. Это были результаты:

Bound     | Trial division     | Sieve (slow)       | Wilson's theorem | Sieve (fast)
----------+--------------------+--------------------+------------------+----------------
1,000     | 2.47 s             | 0.06 s             | 0.03 s           | 0.03 s
10,000    | 246.06 s (4.1 m)   | 1.49 s             | 0.38 s           | 0.14 s
20,000    | 1006.83 s (16.8 m) | 5.22 s             | 1.41 s           | 0.38 s
100,000   | ~ 7 h (estimated)  | 104.65 (1.7 m)     | 35.20 s          | 5.82 s
1,000,000 | ~ 29 d (estimated) | 111136.97s (3.1 h) | 3695.92 s (1 h)  | 418.24 s (7 m)
Деннис
источник
Является ли «медленное» сито всего лишь ситом Эратосфена?
Дорукайхан
Оба. Медленная версия - просто ужасная реализация.
Деннис
5

NARS2000 APL, 7 символов

⍸0π⍳1e6
Улей
источник
3
Добро пожаловать в Программирование Пазлов и Code Golf!
Деннис
4

Golfscript 26 25 24

Изменить (спас еще один символ благодаря Питеру Тейлору):

10 6?,{:x,{)x\%!},,2=},`

Старый код:

10 6?,{.,{)\.@%!},,2=*},`

Этот код имеет только теоретическое значение, так как он невероятно медленный и неэффективный. Я думаю, что это может занять несколько часов, чтобы бежать.

Если вы хотите проверить это, попробуйте, например, только простые числа до 100:

10 2?,{:x,{)x\%!},,2=},`
Кристиан Лупаску
источник
Вы можете сохранить символ, заменив \;на *. (Вы также можете получить намного быстрее для текущего количества символов, найдя первый делитель, а не все из них:10 6?,2>{.),2>{1$\%!}?=},`
Питер Тейлор
@PeterTaylor Спасибо, используя умножение, есть очень аккуратный трюк.
Кристиан Лупаску
Есть еще одно сохранение символа с переменной: заменить .,на :x,и \.@на x\ (пробел из-за экранирования проблем с MD в комментариях) и удалить *.
Питер Тейлор
@PeterTaylor хороший, спасибо! Я отредактировал мой код.
Кристиан Лупаску
4

CJam - 11

1e6,{mp},N*

1e6,- массив 0 ... 999999
{mp},- выбрать простые числа
N*- объединить с помощью новых строк

aditsu
источник
1
Не является ли CJam более новым, чем этот вопрос?
Питер Тейлор
@PeterTaylor о да, это так
aditsu
4

GolfScript, 25 (24) байта

!10 6?,2>{.(@*.)@%!},n*\;

Если формат вывода, указанный в редактируемом вопросе, игнорируется, один байт может быть сохранен:

!10 6?,2>{.(@*.)@%!},`\;

Это будет печатать простые числа как массив (как это делают многие другие решения), а не по одному на строку.

Как это устроено

Общая идея состоит в том, чтобы использовать теорему Вильсона , которая утверждает, что n > 1 является простым тогда и только тогда, когда

                                                      (n - 1)!  = -1 (мод n)

!     # Push the logical NOT of the empty string (1). This is an accumulator.
10 6? # Push 10**6 = 1,000,000.
,2>   # Push [ 2 3 4 … 999,999 ].
{     # For each “N” in this array:
  .(  # Push “N - 1”.
  @   # Rotate the accumulator on top of the stack.
  *   # Multiply it with “N - 1”. The accumulator now hold “(N - 1)!”.
  .)  # Push “(N - 1)! + 1”
  @   # Rotate “N” on top of the stack.
  %!  # Push the logical NOT of “((N - 1)! + 1) % N”.
},    # Collect all “N” for which “((N - 1)! + 1) % N == 0” in an array.
n*    # Join that array by LF.
\;    # Discard the accumulator.

Ориентиры

Быстрее, чем пробное деление, но медленнее, чем сито Эратосфена. Смотрите мой другой ответ .

Деннис
источник
4

Java, 110 байт

void x(){for(int i=1;i++<1e6;)System.out.print(new String(new char[i]).matches(".?|(..+?)\\1+")?"":(i+"\n"));}

Использование унарного деления через регулярные выражения в качестве критерия примитивности.

Аддисон Крамп
источник
1
Хороший подход. Никогда раньше не видел этого премьер-выражения. +1 от меня. Хотя использование вложенного цикла for для простой проверки немного короче . :)
Кевин Круйссен
3

C, 91 88 85 82 81 80 76 72 символов

main(i,j,b){for(;i++<1e6;b++&&printf("%d\n",i))for(j=2;j<i;)b=i%j++&&b;}

Алгоритм ужасно неэффективен, но так как мы занимаемся гольф-кодом, это не должно иметь значения.

Gareth
источник
1
Вы можете легко его укоротить: main(i,j,b){for(;i++<1e6;b++&&printf("%d\n",i))for(j=2;j<i;)b=i%j++&&b;}или что-то вроде этого (поскольку я на самом деле не скомпилировал его)
Ali1S232
Как iобязательно быть 0? Я думаю, что если вы предоставите какой-либо аргумент, он потерпит неудачу. Также, я думаю, jбудет какая-то ошибка типа. Не уверен, bхотя.
Эрик Outgolfer
3

Mathematica 25

Предполагая, что вы не знаете число простых чисел меньше 10 ^ 6:

Prime@Range@PrimePi[10^6]
DavidC
источник
3

J, 16 символов

1]\(#~1&p:)i.1e6

Без требования формата вывода это может быть уменьшено до 13 символов:

(#~1&p:)i.1e6

1]\ просто берет массив простых чисел ранга 1, превращает его в массив ранга 2 и помещает каждое простое число в свою собственную строку - и поэтому формат вывода интерпретатора по умолчанию превращает список из одной строки в одно простое число в строке.

(#~ f) yв основном filter, где fвозвращает логическое значение для каждого элемента в y. i.1e6это диапазон целых чисел [0,1000000), и 1&p:это логическая функция, которая возвращает 1 для простых чисел.

rationalis
источник
3

R 45 45 символов

for(i in 2:1e6)if(sum(!i%%2:i)<2)cat(i," ")

Для каждого числа x от 2 до 1e6 просто выведите его, если число x mod 2 до x, равное 0, меньше 2.

plannapus
источник
Первое число, созданное этим кодом, равно 1, но 1 не является простым числом.
Свен Хоэнштейн
@SvenHohenstein Спасибо, исправлено.
plannapus
3

Баш (433643)

Моя (не очень умная) попытка была использовать фактор для факторинга продукта.

factor ${PRODUCT}

К сожалению, с большими числами продукт, конечно, огромен. Это также заняло более 12 часов, чтобы бежать. Я решил опубликовать это хотя, потому что я думал, что это было уникально.

Вот полный код.

Если бы это было простые числа до шести лет, это было бы разумно.

  factor 30

Ну хорошо, я пытался.

Кевин Кокс
источник
+1 Этот ответ действительно дьявольский. Не совсем предварительно вычисленный результат (он сохраняет немало символов) и гораздо более ужасный для вычислений :) Вполне возможно, что это также пример, который делает оптимизированную работу factorнамного хуже, чем основной алгоритм пробного деления.
Орион
3

C #, 70

Enumerable.Range(1,1e6).Where(n=>Enumerable.Range(2,n).All(x=>x%n!=0))

Вы не увидите много здесь, хотя в течение длительного времени ...

It'sNotALie.
источник
Есть несколько причин, почему это неправильно. (1) Вы не можете неявно преобразовать из a double 1e6в a int, но intэто требуется Range. (2) Внутренний Rangeдолжен принимать не более n-2условий, в противном случае вы будете проверять, n % nчто явно 0. (3) Ты пишешь, x%nкогда хочешь n%x. Исправление этих проблем, что-то вроде этого будет работать: Enumerable.Range(2,999999).Where(n=>Enumerable.Range(2,n-2).All(x=>n%x!=0))однако, это все еще не выводит числа; требование было по одному на строку.
Джеппе Стиг Нильсен