Elenco di numeri primi inferiori a un milione


56

Questa è la mia prima domanda sul golf del codice, e molto semplice, quindi mi scuso in anticipo se potrei aver infranto qualsiasi linea guida della comunità.

Il compito è di stampare, in ordine crescente, tutti i numeri primi meno di un milione. Il formato di output dovrebbe essere un numero per riga di output.

Lo scopo, come per la maggior parte degli invii di golf di codice, è di ridurre al minimo le dimensioni del codice. Anche l'ottimizzazione per il runtime è un vantaggio, ma è un obiettivo secondario.


12
Non è un duplicato esatto, ma è essenzialmente solo un test di primalità, che è un componente di una serie di domande esistenti (ad esempio codegolf.stackexchange.com/questions/113 , codegolf.stackexchange.com/questions/5087 , codegolf.stackexchange. com / questions / 1977 ). FWIW, una linea guida che non è seguita abbastanza (anche da persone che dovrebbero conoscere meglio) è di pre-proporre una domanda nel meta sandbox meta.codegolf.stackexchange.com/questions/423 per critiche e discussioni su come può essere migliorato prima che le persone inizino a rispondere.
Peter Taylor,

Ah, sì, ero preoccupato che questa domanda fosse troppo simile alla pletora di domande sui numeri primi già presenti.
Delan Azabani,

2
@ GlennRanders-Pehrson Perché 10^6è ancora più breve;)
ɐɔıʇǝɥʇuʎs

1
Qualche anno fa ho presentato una voce IOCCC che stampa numeri primi con solo 68 caratteri in C - purtroppo si ferma ben poco meno di un milione, ma potrebbe essere di interesse per alcuni: computronium.org/ioccc.html
Computronium

1
@ ɐɔıʇǝɥʇuʎs Che ne dici di 1e6:-D
Tito

Risposte:


33

Mathematica , 17 24

Solo per confronto:

Prime@Range@78498

Come notato in un commento, non sono riuscito a fornire un numero primo per riga; correzione:

Column@Prime@Range@78498

4
Prime~Array~78498anche 17 :)
chyanog

Sarebbe nove byte in mthmca, se fosse rilasciato.
Michael Stern,

Ciò viola la condizione di un numero primo per riga di output. Prefisso con Print/@e chiusura con ;per impedire l'output di un lungo elenco di Nullcorrezioni che, al costo di 8 caratteri extra.
Celtschk,

@celtschk Non so se l'ho mancato o ignorato cinque anni fa.
Mr.Wizard,

1
Beh, ho sicuramente perso che era di cinque anni fa :-)
Celtschk

27

Python 3, 46 byte

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

Quando il ciclo raggiunge il test k, ha iterativamente calcolato il fattoriale quadrato P=(k-1)!^2. Se kè primo, allora non appare nel prodotto 1 * 2 * ... * (k-1), quindi non è un fattore di P. Ma, se è composto, tutti i suoi fattori primi sono più piccoli e quindi nel prodotto. La quadratura è effettivamente necessaria solo per k=4evitare di essere falsamente chiamata primo.

Più fortemente, dal teorema di Wilson segue che quando kè primo è P%kuguale 1. Anche se qui abbiamo solo bisogno che sia diverso da zero, è utile in generale che P%ksia una variabile indicatore per stabilire se kè primo.


23

C, 61 caratteri

Quasi esattamente uguale a questo (la domanda è quasi esattamente la stessa).

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

Ottenuto SEG-FAULTdopo la stampa881
manav mn il

7
@Manav, forse hai compilato senza ottimizzazioni. Si basa su un buon ottimizzatore, che rimuoverà la ricorsione.
ugoren,

4
Sì aggiungendo -O3per gccrisolvere il problema !!
manav mn,

Questo metodo è pazzo. Lo adoro.
Todd Lehman,

2
Posso portarti a 57 byten=2;main(m){n<1e6&&main(m<2?printf("%d\n",n),n:m-++n%m);}
Albert Renshaw,

22

MATLAB (16) (12)

Sfortunatamente, questo emette su una sola riga:

primes(1000000)

ma questo è risolto da una semplice trasposizione matriciale:

primes(1000000)'

e posso ritagliare alcuni caratteri usando la notazione esponenziale (come suggerito nei commenti):

primes(1e6)'

5
Utilizzando al 1e6posto di 1000000aiuta anche qui.
Orione,

@orion Quello renderebbe 11 caratteri
Axoren il

@Axoren che non include 'alla fine
Stan Strum

20

Bash (37 caratteri)

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

(60 caratteri)

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

sul mio computer (2,0 GHz cpu, 2 GB di RAM) richiede 14 secondi.


Questo può essere migliorato per: seq 2 1000000|factor|sed 's/[0-9]*: //g;/^.* .*$/ d'
Delan Azabani,

sì hai ragione. Ho scritto il mio comando sed pulito, non golfato: P
Saeedn

3
seq 1e6|factor|awk '$0=$2*!$3'è un po 'più corto.
Dennis,

1
seq, factor e sed sono programmi esterni, questo potrebbe anche essere c pdove c è un collegamento simbolico a cat e p è un file di testo con numeri primi fino a un milione ... puoi farlo con i builtin della shell?
technosaurus

7
@technosaurus seqe ci factorsono coreutils, quindi è legittimo. sedè anche abbastanza onnipresente. coreutilspuò essere trattato come un built-in. Bash senza coreutils è come C ++ senza STL.

16

J, 21 caratteri

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

che può essere abbreviato in

1[\p:i.78498

se sai quanti numeri primi sono inferiori a 1000000.


2
Utilizzando elementi enfile ,., invece di 1 [\\ per salvare un personaggio. Rimuovere la parentesi inutili, e utilizzare la notazione esponenziale: 1e6.
Omar,

Sono venuto su questo: ,.i.&.(p:^:_1)1e6non più breve (dopo aver applicato i suggerimenti di @Omar) ma ho trovato interessante l'uso di under.
Kaao,

10

PowerShell, 47 44 byte

Molto lento, ma il più breve che potessi inventare.

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

PowerShell, 123 byte

Questo è molto più veloce; tutt'altro che ottimale, ma un buon compromesso tra efficienza e brevità.

 $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

Bash, 30 byte

Dato che saeedn non agirà in base al mio suggerimento - che è sia più breve che più veloce del suo approccio - ho pensato di pubblicare la mia risposta:

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

Come funziona

seq 1e6

elenca tutti i numeri interi positivi fino a 1.000.000.

factor

li fattori uno per uno. Per i primi dieci, l'output è il seguente:

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

Finalmente,

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

cambia l'intera riga ( $0) nel prodotto del secondo campo (il primo fattore primo) e la negazione logica del terzo campo ( 1se è un fattore primo o inferiore, 0altrimenti).

Questo sostituisce le linee corrispondenti ai numeri primi con il numero stesso e tutte le altre linee con zeri. Poiché awk stampa solo i valori di verità, verrà stampato solo il numero primo.


4
awk '$0=$2*!$3'è fantastico!
yeti,

8

Ruby 50 41

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

2
Non è necessario .to_a, poiché già include Enumerableselect . Puoi anche usare la notazione abbreviata per Symbol # to_proc per accorciarla ulteriormente: p (2..1e6).select &:prime?(1 non è primo)
Ventero,

@Ventero grazie mille! Non sapevo del simbolo # to_proc. Devo prestare maggiore attenzione alle scorciatoie offerte da Ruby.
Cristian Lupascu,

2
Versione più corta require'prime';p Prime.take 78498.
Hauleth,

@ ŁukaszNiemier Great! Penso che sia così diverso che puoi pubblicarlo come risposta separata.
Cristian Lupascu,

Buon uso di un buon vecchio "ragazzo di campagna"
DoctorHeckle,

8

Bash, 37

Golferà di più, se posso ...

La maggior parte di questi sta cercando di analizzare factoril formato di output scomodo.

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

Ci vogliono circa 5,7 secondi per completare sulla mia macchina.

(È appena successo che il mio post è stato il primo ad andare nella seconda pagina di risposte, quindi nessuno lo vedrà ...)

Vecchia soluzione

Questo è più lungo e più lento (richiede 10 secondi).

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

2
Caspita - non mi sono mai imbattuto factorprima, ma è proprio lì in coreutils!
Digital Trauma,

1
Elimina un personaggio: seq 1e6|factor|grep -oP "(?<=: )\d+$"con uno sguardo perl-grep
Digital Trauma,

@DigitalTrauma come funziona

1
-Pabilita le regex in stile perl. (?<=: )è un aspetto positivo per la stringa ":". Fondamentalmente questo dice che ":" deve venire prima di ciò che corrisponde \d+$, ma in realtà non fa parte della corrispondenza, quindi l' -oopzione ci dà solo un numero corrispondente dopo i due punti, cioè fornisce solo numeri in cui c'è solo un fattore, ovvero primo.
Trauma digitale

@DigitalTrauma aggiunto

8

Python 3.x: 66 caratteri

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

Soluzione più efficiente: 87 caratteri

Basato sul setaccio di Eratostene.

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
Il primo stampa erroneamente 0e 1. Puoi risolvere questo problema usando invece range(2,10**6). Inoltre, penso che l' ifaffermazione debba essere su una riga separata dall'out foro si ottiene un errore.
xnor

@xnor: risolto.
dan04

8

Haskell, 51

mapM print [n|n<-[2..10^6],all((>0).rem n)[2..n-1]]

È possibile passare mapM_a mapM, il valore restituito non verrà stampato e questo è Code Golf. ;)
Dogbert,

perché ci sono spazi extra dopo la stampa e in (> 0)?
orgoglioso haskeller il

bella presa! grazie
pt2121

È possibile sostituire 999999 con 10 ^ 6. E si prega di aggiornare il conteggio dei byte - 63 non può essere corretto.
user2845840

@utente2845840 ok grazie. buona idea!
pt2121,

8

APL, 15

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

Il mio interprete ha riscontrato problemi di memoria, ma funziona in teoria.


Come? Puoi dare un deskription?
Rasmus Damgaard Nielsen,

È necessario un fronte per creare un numero per riga e non è necessario ,.
Adám,

@RasmusDamgaardNielsen sono i primi numeri interi. 1↓lascia cadere il primo. p←assegna a p. p∘.×pcrea una tabella di moltiplicazione. p~rimuove da p qualunque cosa sia sulla destra. ( ,non è necessario, ravviva il tavolo in un elenco.)
Adám

8

Perl, 49 byte

Espressione regolare kung fu :)

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

Versione non golfata:

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

Non ho nemmeno fatto progressi del 10% mentre scrivo questo post!

Fonte per il regex: http://montreal.pm.org/tech/neil_kandalgaonkar.shtml


2
mi ha ispirato a scrivere una versione perl6. inoltre, 1000000può essere scritto10**6
pabo

1
Inoltre, 1000000 può essere scritto 1E6
mob

Aggiornato la mia risposta. Grazie @mob
Gowtham,

È sempre stata una mia regex preferita, ma è necessario ricordare che fallisce in modo spettacolare una volta arrivati ​​a numeri più alti, a causa del fatto che sta convertendo numeri enormi in unari. Questa regex potrebbe non funzionare per trovare numeri primi tra le centinaia di migliaia e oltre, a seconda della propria configurazione della lingua (e della propria macchina.)
Codefun64

7

Julia, 11

primes(10^6)

Sembra che i built-in ottengano voti, inoltre ho bisogno di più parole per una risposta più lunga.


7

J (15 o 9)

Non posso credere a questo battito di Mathematica (anche se è solo un singolo da 2 caratteri)

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

O:

p:i.78498

1
... The output format should be one number per line of output.Ecco perché la mia risposta inizia con 1[\ .
Gareth,

6

gs2, 5 byte

Codificato in CP437:

∟)◄lT

1C 29spinge un milione, 11 6Cè numeri primi in basso, 54è linee di spettacolo.


5

GolfScript, 22/20 (20/19) byte

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

A scapito della velocità, il codice può essere ridotto di due byte:

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

Se il formato di output specificato nella domanda modificata viene ignorato (che è ciò che fanno molte delle risposte esistenti), due byte possono essere salvati nella versione veloce e uno può essere salvato in quella lenta:

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

Questo stamperà un ulteriore LF dopo i numeri primi per la versione veloce e stamperà i numeri primi come un array per quello lento.

Come funziona

Entrambe le versioni sono implementazioni del setaccio di Eratostene .

La versione veloce effettua le seguenti operazioni:

  1. Imposta A = [ 2 3 4 … 999,999 ]e | = [ 0 1 2 … 999,999 ].

  2. Imposta N = A[0]e stampa N.

  3. Raccogli tutti gli elementi dell'N-esimo da |dentro C. Questi sono i multipli di N.

  4. Set A = A - C.

  5. Se Anon è vuoto, tornare 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.

La versione lenta funziona in modo simile, ma invece di rimuovere successivamente multipli del minimo di "A" (che è sempre primo), rimuove i multipli di tutti gli interi positivi inferiori a 1.000.000.

Competitività

In assenza di funzioni matematiche integrate per la fattorizzazione o il controllo della primalità, tutte le soluzioni GolfScript saranno molto grandi o molto inefficienti.

Pur essendo tutt'altro che efficiente, penso di aver raggiunto un discreto rapporto velocità-dimensioni. Al momento della sua presentazione, questo approccio sembra essere il più breve di quelli che non utilizzano nessuno dei summenzionati incorporati. Dico sembra perché non ho idea di come funzionano alcune delle risposte ...

Ho analizzato tutte e quattro le soluzioni GolfScript presentate: w0lf (divisione di prova), l'altra mia risposta (teorema di Wilson) e le due di questa risposta. Questi erano i risultati:

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)

Il setaccio "lento" è solo un setaccio di Eratostene?
Dorukayhan,

Entrambi sono. La versione lenta è solo una terribile implementazione.
Dennis,

5

NARS2000 APL, 7 caratteri

⍸0π⍳1e6

3
Benvenuto in Programmazione di puzzle e codice golf!
Dennis,

4

Golfscript 26 25 24

Modifica (salvato un altro carattere grazie a Peter Taylor):

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

Vecchio codice:

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

Questo codice ha solo un valore teorico, in quanto è incredibilmente lento e inefficiente. Penso che potrebbero volerci ore per correre.

Se desideri provarlo, prova ad esempio solo i numeri primi fino a 100:

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

Puoi salvare un personaggio sostituendolo \;con *. (Puoi anche ottenere molto più velocemente per il conteggio attuale dei personaggi trovando il primo divisore anziché tutti:10 6?,2>{.),2>{1$\%!}?=},`
Peter Taylor,

@PeterTaylor Grazie, usando la moltiplicazione c'è un trucco molto accurato.
Cristian Lupascu,

C'è un ulteriore risparmio di caratteri con una variabile: sostituisci .,con :x,e \.@con x\ (gli spazi bianchi sono dovuti a problemi di escape con MD nei commenti) e rimuovi *.
Peter Taylor,

@PeterTaylor bravo, grazie! Ho modificato il mio codice.
Cristian Lupascu,

4

CJam - 11

1e6,{mp},N*

1e6,- matrice di 0 ... 999999
{mp},- seleziona numeri primi
N*- unisciti con le nuove linee


1
CJam non è più recente di questa domanda?
Peter Taylor,

@PeterTaylor oh, sì, lo è
aditsu,

4

GolfScript, 25 (24) byte

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

Se il formato di output specificato nella domanda modificata viene ignorato, è possibile salvare un byte:

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

Questo stamperà i numeri primi come un array (come fanno molte altre soluzioni) anziché uno per riga.

Come funziona

L'idea generale è di usare il teorema di Wilson , che afferma che n > 1 è il primo se e solo se

                                                      (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.

benchmark

Più veloce della divisione di prova, ma più lento del setaccio di Eratostene. Vedi la mia altra risposta .



3

C, 91 88 85 82 81 80 76 72 caratteri

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

L'algoritmo è terribilmente inefficiente, ma dal momento che stiamo facendo code-golf non dovrebbe importare.


1
puoi accorciarlo facilmente: main(i,j,b){for(;i++<1e6;b++&&printf("%d\n",i))for(j=2;j<i;)b=i%j++&&b;}o un'idea del genere (dal momento che in realtà non l'ho compilata)
Ali1S232,

Quanto è isicuro essere 0? Penso che, se fornisci qualche argomento, fallirà. Inoltre, penso che javrà una sorta di errore di tipo. Non sono sicuro bperò.
Erik the Outgolfer,

3

Mathematica 25

Supponendo di non conoscere il numero di numeri primi inferiori a 10 ^ 6:

Prime@Range@PrimePi[10^6]

3

J, 16 caratteri

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

Senza il requisito del formato di output, questo può essere ridotto a 13 caratteri:

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

1]\ prende semplicemente l'array di numeri primi di rango 1, lo trasforma in un array di livello 2 e mette ciascun numero primo sulla propria riga - e quindi il formato di output predefinito dell'interprete trasforma l'elenco di una riga in un numero primo per riga.

(#~ f) yè fondamentalmente filter, dove frestituisce un valore booleano per ogni elemento in y. i.1e6è l'intervallo di numeri interi [0,1000000) ed 1&p:è una funzione booleana che restituisce 1 per i numeri primi.


3

R, 45 43 caratteri

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

Per ogni numero x da 2 a 1e6, è sufficiente emetterlo se il numero di x mod da 2 a x che è uguale a 0 è inferiore a 2.


Il primo numero prodotto da questo codice è 1, ma 1 non è un numero primo.
Sven Hohenstein,

@SvenHohenstein Grazie, corretto.
plannapus,

3

Bash (433643)

Il mio (non così intelligente) tentativo era di utilizzare il fattore per fattorizzare il prodotto.

factor ${PRODUCT}

Sfortunatamente con grandi numeri il prodotto è ovviamente enorme. Ci sono volute anche più di 12 ore per l'esecuzione. Ho deciso di pubblicarlo perché pensavo fosse unico.

Ecco il codice completo.

Se fossero numeri primi sotto i sei sarebbe ragionevole.

  factor 30

Oh bene, ci ho provato.


+1 Questa risposta è veramente diabolica. Risultato non del tutto precalcolato (salva un bel po 'di caratteri) e molto più terribile da calcolare :) È probabilmente anche un esempio che rende le factorprestazioni ottimizzate molto peggiori dell'algoritmo di base della divisione di prova.
Orione,

3

C #, 70

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

Non vedrai molto qui per molto tempo ...


Ci sono diverse ragioni per cui questo è sbagliato. (1) Non è possibile convertire implicitamente da a double 1e6a an int, ma intè richiesto da Range. (2) L'interno Rangedeve prendere la maggior parte dei n-2termini, altrimenti testerai n % nchiaramente 0. (3) Scrivi x%nquando vuoi n%x. Risolvendo questi problemi, qualcosa del genere funzionerà: Enumerable.Range(2,999999).Where(n=>Enumerable.Range(2,n-2).All(x=>n%x!=0))Tuttavia, questo non genera ancora i numeri; il requisito era uno per riga.
Jeppe Stig Nielsen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.