Список простих чисел під мільйон


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
Кілька років тому я представив запис МОКЦ, який друкує праймери лише 68 символами на С - на жаль, це не вистачає мільйона, але це може зацікавити когось
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виправлень s, що коштують 8 зайвих символів.
celtschk

@celtschk Я не знаю, чи пропустив чи не звернув увагу п’ять років тому.
Mr.Wizard

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

C, 61 символів

Майже точно такий же, як і цей (питання майже точно таке ж).

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

Отримав SEG-FAULTпісля друку881
манав

7
@Manav, можливо, ви склали без оптимізацій. Він покладається на хороший оптимізатор, який видалить рекурсію.
ugoren

4
Так, додавання -O3для gccвирішення проблеми !!
manav mn

Цей спосіб божевільний. Я це люблю.
Тодд Леман

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, яка не включає 'в кінці
Стен Струм

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 - це посилання на кішку, а 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 байт

Оскільки saeedn не буде діяти на мою пропозицію - що і коротше, і швидше, ніж його підхід - я подумав, що опублікую власну відповідь:

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

Як це працює

seq 1e6

перераховує всі натуральні числа до 1 000 000.

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'дивовижно класно!
yeti

8

Рубін 50 41

require'mathn'
p (2..1e6).select &:prime?

2
Немає необхідності .to_a, оскільки Рахункова вже включає в себе select. Ви також можете скористатись скороченим позначенням Symbol # to_proc для подальшого скорочення: p (2..1e6).select &:prime?(1 не є основним)
Вентеро,

@ Вентеро велике спасибі! Я не знав про символ # to_proc. Я мушу приділити більше уваги ярликам пропозицій Ruby.
Крістіан Лупаску

2
Коротша версія require'prime';p Prime.take 78498.
Hauleth

@ ŁukaszNiemier Чудово! Я думаю, це настільки різне, що ви можете опублікувати це як окрему відповідь.
Крістіан Лупаску

Гарне використання деяких хороших ol 'country boy mathn'
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+$"з перламутровим виглядом позаду
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заява має бути в окремому рядку від виходу forабо ви отримаєте помилку.
xnor

@xnor: виправлено.
dan04

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 не може бути правильним.
користувач2845840

@ user2845840 добре дякую. гарна ідея!
pt2121

8

APL, 15

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

Мій перекладач зіткнувся з проблемами пам’яті, але це працює в теорії.


Як? Чи можете ви дати опис?
Расмус Дамгаард Нільсен

Вам потрібно спереду, щоб зробити одне число на рядок, і вам не потрібно ,.
Адам

@RasmusDamgaardNielsen - це перші цілі числа. 1↓краплі першої. p←призначає на с. p∘.×pскладає таблицю множення. p~видаляє з p те, що знаходиться праворуч. ( ,не потрібно, він розбиває таблицю до списку.)
Adám

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
pabo

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-й елемент з |вC . Це множини N.

  4. Встановити 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.

Повільна версія працює аналогічно, але замість послідовного видалення кратних мінімумів "A" (що завжди є простим), вона видаляє кратні всі додатні цілі числа нижче 1 000 000.

Конкурентоспроможність

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

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

Я порівняв усі чотири представлені рішення GolfScript: w0lf's (пробний поділ), інша моя відповідь (теорема Вілсона) та два відповіді. Такі результати:

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
Ласкаво просимо до головоломки програмування та коду для гольфу!
Денніс

4

Гольфскрипт 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 (mod 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-over для перевірки праймів трохи коротше . :)
Кевін Кройсейсен

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хоча.
Ерік Аутгольфер

3

Математика 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 43 символи

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 Спасибі, виправлено.
планнапус

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) Ви не можете неявно перетворювати з а double 1e6в а 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.