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


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

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является ли простое число.


23

С, 61 символ

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

n=2;main(m){n<1e6&&main(m<2?printf("%d\n",n),n:n%m?m-1:n++);}

Получил 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)'

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 секунд.


Это может быть улучшено до: 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.


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


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)

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]]

Вы можете изменить mapM_на mapM, возвращаемое значение не будет напечатано, и это Code Golf. ;)
Догберт

почему после печати и в (> 0) есть дополнительные пробелы?
гордый haskeller

Хорошо поймал! спасибо
pt2121

Вы можете заменить 999999 на 10 ^ 6. И, пожалуйста, обновите ваш счетчик байтов - 63 не может быть правильным.
user2845840

@ user2845840 ок, спасибо. хорошая идея!
pt2121

8

APL, 15

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

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


Как? Можете ли вы дать описание?
Расмус Дамгаард Нильсен

Вам нужен спереди, чтобы сделать один номер в строке, и вам не нужно ,.
Адам

@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


2
вдохновил меня написать версию perl6. Кроме того, 1000000может быть написано10**6
Пабо

1
Также 1000000 можно написать 1E6
моб

Обновил мой ответ. Спасибо @mob
Gowtham

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

7

Юлия, 11

primes(10^6)

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


7

J (15 или 9)

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

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

Или же:

p:i.78498

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)

Является ли «медленное» сито всего лишь ситом Эратосфена?
Дорукайхан

Оба. Медленная версия - просто ужасная реализация.
Деннис


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*- объединить с помощью новых строк


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;}

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


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]

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 для простых чисел.


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.


Первое число, созданное этим кодом, равно 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))

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


Есть несколько причин, почему это неправильно. (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))однако, это все еще не выводит числа; требование было по одному на строку.
Джеппе Стиг Нильсен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.