Lista de números primos abaixo de um milhão

56

Esta é a minha primeira pergunta sobre código de golfe, e uma pergunta muito simples, por isso peço desculpas antecipadamente por ter quebrado as diretrizes da comunidade.

A tarefa é imprimir, em ordem crescente, todos os números primos menores que um milhão. O formato de saída deve ser um número por linha de saída.

O objetivo, como na maioria dos envios de código de golfe, é minimizar o tamanho do código. A otimização para o tempo de execução também é um bônus, mas é um objetivo secundário.

Delan Azabani
fonte
12
Não é uma cópia exata, mas é essencialmente o teste apenas primality, que é um componente de uma série de perguntas existentes (por exemplo codegolf.stackexchange.com/questions/113 , codegolf.stackexchange.com/questions/5087 , codegolf.stackexchange. com / questions / 1977 ). FWIW, uma diretriz que não é seguida o suficiente (mesmo por pessoas que deveriam saber melhor) é pré-propor uma pergunta na meta sandbox meta.codegolf.stackexchange.com/questions/423 para críticas e discussão de como pode ser melhorou antes que as pessoas começassem a responder.
Peter Taylor
Ah, sim, eu estava preocupado com essa questão ser muito semelhante à infinidade de questões relacionadas a números primos já existentes.
Delan Azabani
2
@ GlennRanders-Pehrson Porque 10^6é ainda menor;)
ɐɔıʇǝɥʇuʎs
11
Alguns anos atrás, enviei uma entrada do IOCCC que imprime números primos com apenas 68 caracteres em C - infelizmente, chega a um milhão, mas pode ser interessante para alguns: computronium.org/ioccc.html
Computronium
11
@ ɐɔıʇǝɥʇuʎs Que tal 1e6:-D
Tito

Respostas:

33

Mathematica , 17 24

Apenas para comparação:

Prime@Range@78498

Como observado em um comentário, falhei em fornecer um número primo por linha; correção:

Column@Prime@Range@78498
Mr.Wizard
fonte
4
Prime~Array~78498Também 17 :)
chyanog 5/04
Seriam nove bytes em mthmca, se isso fosse lançado.
Michael Stern
Isso viola a condição de um prime por linha de saída. Prefixar Print/@e terminar com ;para impedir a saída de uma longa lista de Nulls correções que, ao custo de 8 caracteres extras.
Celtschk
@celtschk Não sei se perdi ou desconsiderei isso há cinco anos.
Mr.Wizard
11
Bem, eu definitivamente perdida que era de cinco anos atrás :-)
celtschk
27

Python 3, 46 bytes

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

No momento em que o loop chega ao teste k, ele iterativamente calculou o fatorial ao quadrado P=(k-1)!^2. Se kfor primo, não aparecerá no produto 1 * 2 * ... * (k-1), portanto não é um fator de P. Mas, se for composto, todos os seus principais fatores são menores e, portanto, no produto. A quadratura só é realmente necessária para parar k=4de ser falsamente chamada de primo.

Mais fortemente, segue-se do teorema de Wilson que quando ké primo, P%ké igual 1. Embora apenas precisemos que seja diferente de zero aqui, é útil, em geral, que P%kseja uma variável indicadora de se ké primo.

xnor
fonte
23

C, 61 caracteres

Quase exatamente o mesmo que este (a questão também é quase exatamente a mesma).

n=2;main(m){n<1e6&&main(m<2?printf("%d\n",n),n:n%m?m-1:n++);}
Ugoren
fonte
Obtido SEG-FAULTapós a impressão881
manav mn
7
@ Manav, talvez você tenha compilado sem otimizações. Ele conta com um bom otimizador, que removerá a recursão.
Ugoren
4
Sim adicionando -O3para gccresolver o problema !!
precisa saber é o seguinte
Este método é insano. Eu amo isso.
Todd Lehman
2
Eu posso levá-lo a 57 bytesn=2;main(m){n<1e6&&main(m<2?printf("%d\n",n),n:m-++n%m);}
Albert Renshaw
22

MATLAB (16) (12)

Infelizmente, isso gera uma única linha:

primes(1000000)

mas isso é resolvido por uma simples transposição de matriz:

primes(1000000)'

e posso recortar alguns caracteres usando notação exponencial (como sugerido nos comentários):

primes(1e6)'
MBraedley
fonte
5
Usando em 1e6vez de 1000000ajuda aqui também.
orion 14/05
@orion Isso daria 11 caracteres #
Axoren # 31/14
@Axoren que não incluem o 'no final
Stan Strum
20

Bash (37 caracteres)

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

(60 caracteres)

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

no meu computador (CPU de 2,0 GHz, 2 GB de RAM) leva 14 segundos.

saeedn
fonte
Isso pode ser melhorado para: seq 2 1000000|factor|sed 's/[0-9]*: //g;/^.* .*$/ d'
Delan Azabani
sim, você está certo. Eu escrevi o meu comando sed limpo, não golfed: P
saeedn
3
seq 1e6|factor|awk '$0=$2*!$3'é um pouco mais curto.
Dennis
11
seq, factor e sed são programas externos; pode ser c ponde c é um link simbólico para cat ep é um arquivo de texto com números primos de até um milhão ... você pode fazê-lo com shell embutidos?
Technosaurus 13/05
7
@technosaurus seqe factorestão coreutils, por isso é legítimo. sedtambém é bastante onipresente. coreutilspode ser tratado como um built-in. Bash sem coreutils é como C ++ sem o STL.
16

J, 21 caracteres

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

que pode ser reduzido para

1[\p:i.78498

se você souber quantos números primos existem abaixo de 1000000.

Gareth
fonte
2
Usando itens de enfile,, em ,.vez de 1 [\\ para salvar um caractere. Remover o parêntese desnecessário, e usar notação exponencial: 1e6.
Omar
,.i.&.(p:^:_1)1e6Comecei com isso: Não é mais curto (depois de aplicar as sugestões do @Omar), mas achei o uso de sob interessante.
kaoD
10

PowerShell, 47 44 bytes

Muito lento, mas o mais curto que consegui.

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

PowerShell, 123 bytes

Isso é muito mais rápido; longe de ser o ideal, mas um bom compromisso entre eficiência e brevidade.

 $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
fonte
9

Ruby 34

require'prime';p Prime.take 78498
Hauleth
fonte
9

Bash, 30 bytes

Como saeedn não vai agir de acordo com minha sugestão - que é mais curta e mais rápida que a abordagem dele -, pensei em postar minha própria resposta:

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

Como funciona

seq 1e6

lista todos os números inteiros positivos até 1.000.000.

factor

fatores-los um por um. Para os dez primeiros, a saída é a seguinte:

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'

altera a linha inteira ($0 ) para o produto do segundo campo (o primeiro fator primo) e a negação lógica do terceiro campo ( 1se for um fator primo ou menos, 0caso contrário).

Isso substitui as linhas correspondentes aos números primos pelo próprio número e todas as outras linhas pelos zeros. Como o awk imprime apenas valores reais, apenas o número principal será impresso.

Dennis
fonte
4
awk '$0=$2*!$3'é legal demais!
yeti
8

Ruby 50 41

require'mathn'
p (2..1e6).select &:prime?
Cristian Lupascu
fonte
2
Não é necessário .to_a, pois o Enumerable já inclui select. Você também pode usar a notação abreviada do Symbol # to_proc para abreviá-lo ainda mais: p (2..1e6).select &:prime?(1 não é primo)
Ventero
@Ventero muito obrigado! Eu não sabia sobre o símbolo # to_proc. Tenho que prestar mais atenção aos atalhos que Ruby oferece.
Cristian Lupascu
2
Versão mais curta require'prime';p Prime.take 78498.
Hauleth
@ ŁukaszNiemier Ótimo! Eu acho que é tão diferente que você pode publicá-la como uma resposta separada.
Cristian Lupascu
Bom uso do 'menino mathn país' algum bom ol
DoctorHeckle
8

Bash, 37

Golf mais, se eu puder ...

A maior parte disso está tentando analisar factoro formato de saída estranho.

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

Leva 5,7 ou mais segundos para concluir na minha máquina.

(Aconteceu que o meu post foi o primeiro a ir para a segunda página de respostas, então ninguém vai vê-lo ...)

Solução antiga

Isso é mais longo e mais lento (leva 10 segundos).

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

fonte
2
Uau - eu nunca me deparei com isso factorantes, mas aí está o coreutils!
Digital Trauma
11
Raspar um caractere: seq 1e6|factor|grep -oP "(?<=: )\d+$"com um lookbehind perl-grep
Digital Trauma
@DigitalTrauma como isso funciona
11
-Ppermite regexes no estilo perl. (?<=: )é um olhar positivo para a cadeia ":". Basicamente, isso diz que ":" deve vir antes do que corresponde \d+$, mas na verdade não faz parte da correspondência; portanto, a -oopção nos fornece um número correspondente após os dois pontos, ou seja, apenas fornece números onde há apenas um fator, ou seja, primo.
Digital Trauma
@DigitalTrauma adicionou
8

Python 3.x: 66 caracteres

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

Solução mais eficiente: 87 caracteres

Baseado na peneira de Eratóstenes.

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
fonte
11
O primeiro imprime erroneamente 0e 1. Você pode corrigir isso usando range(2,10**6). Além disso, acho que a ifdeclaração deve estar em uma linha separada da saída forou você recebe um erro.
Xnor 13/05
@ xnor: Corrigido.
precisa saber é
8

Haskell, 51

mapM print [n|n<-[2..10^6],all((>0).rem n)[2..n-1]]
pt2121
fonte
Você pode alterar mapM_para mapM, o valor de retorno não será impresso e este é o Code Golf. ;)
Dogbert
por que existem espaços extras após a impressão e em (> 0)?
haskeller orgulhoso
boa pegada! obrigado
pt2121
Você pode substituir 999999 por 10 ^ 6. E atualize sua contagem de bytes - 63 não pode estar certo.
user2845840
@ user2845840 ok obrigado. boa ideia!
2121
8

APL, 15

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

Meu intérprete teve problemas de memória, mas funciona em teoria.

TwiNight
fonte
Quão? Você pode dar uma descrição?
Rasmus Damgaard Nielsen
Você precisa de um na frente para fazer um número por linha e não precisa do ,.
Adám 03/09/15
@RasmusDamgaardNielsen são os primeiros números inteiros. 1↓derruba o primeiro. p←atribui a p. p∘.×pfaz uma tabuada de multiplicação. p~remove de p o que estiver à direita. ( ,Não é necessária, ela Ravels a tabela para uma lista.)
Adám
8

Perl, 49 bytes

Expressão regular kung fu :)

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

Versão não destruída:

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

Nem sequer fez 10% de progresso enquanto digito este post!

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

Gowtham
fonte
2
me inspirou a escrever uma versão perl6. Também, 1000000pode ser escrito10**6
pabo
11
Além disso, 1000000 pode ser escrito 1E6
mob
Atualizei minha resposta. Obrigado @mob
Gowtham
Sempre foi uma das minhas regex favoritas, mas é preciso lembrar que ela falha espetacularmente quando você atinge números mais altos - devido ao fato de estar convertendo grandes números em unários. Este regex pode não funcionar para encontrar números primos na casa das centenas de milhares e além, dependendo da configuração da língua (e sua máquina.)
Codefun64
7

Julia, 11

primes(10^6)

Parece que os ins internos estão recebendo votos positivos, e eu precisava de mais palavras para obter respostas mais longas.

gggg
fonte
7

J (15 ou 9)

Eu não posso acreditar nessa batida do Mathematica (mesmo que seja apenas um por 2 caracteres)

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

Ou:

p:i.78498
ɐɔıʇǝɥʇuʎs
fonte
11
... The output format should be one number per line of output.É por isso que minha resposta começa com 1[\ .
Gareth
6

gs2, 5 bytes

Codificado no CP437:

∟)◄lT

1C 29empurra um milhão, 11 6Cé primos abaixo, 54é mostra linhas.

Lynn
fonte
5

GolfScript, 22/20 (20/19) bytes

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

À custa da velocidade, o código pode ser reduzido em dois bytes:

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

Se o formato de saída especificado na pergunta editada for desconsiderado (que é o que muitas das respostas existentes fazem), dois bytes podem ser salvos na versão rápida e um na versão lenta:

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

Isso imprimirá um LF adicional após os primos da versão rápida e os primos como uma matriz do lento.

Como funciona

Ambas as versões são implementações da peneira de Eratóstenes .

A versão rápida faz o seguinte:

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

  2. Conjunto N = A[0] e imprimir N.

  3. Colete todos os N-ésimos elementos de | dentro C. Estes são os múltiplos de N.

  4. Set A = A - C.

  5. Se Anão estiver vazio, volte para 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 versão lenta funciona de maneira semelhante, mas, em vez de remover sucessivamente múltiplos do mínimo de "A" (que é sempre primo), remove múltiplos de todos os números inteiros positivos abaixo de 1.000.000.

Competitividade

Na ausência de funções matemáticas embutidas para fatorar ou verificar a primalidade, todas as soluções GolfScript serão muito grandes ou muito ineficientes.

Embora ainda esteja longe de ser eficiente, acho que atingi uma proporção decente de velocidade / tamanho. No momento da submissão, essa abordagem parece ser a mais curta entre as que não usam nenhum dos embutidos mencionados acima. Eu digo parece que não tenho ideia de como algumas das respostas funcionam ...

Comparei todas as quatro soluções GolfScript enviadas: w0lf (divisão de teste), minha outra resposta (teorema de Wilson) e as duas respostas. Estes foram os resultados:

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)
Dennis
fonte
A peneira "lenta" é apenas uma peneira de Eratóstenes?
Dorukayhan 27/05
Ambos são. A versão lenta é apenas uma implementação horrível.
Dennis
5

NARS2000 APL, 7 caracteres

⍸0π⍳1e6
A colméia
fonte
3
Bem-vindo à programação de quebra-cabeças e código de golfe!
Dennis
4

Golfscript 26 25 24

Editar (salvou mais um caractere graças a Peter Taylor):

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

Código antigo:

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

Este código tem apenas valor teórico, pois é incrivelmente lento e ineficiente. Eu acho que pode levar horas para correr.

Se você deseja testá-lo, tente, por exemplo, apenas os números primos de até 100:

10 2?,{:x,{)x\%!},,2=},`
Cristian Lupascu
fonte
Você pode salvar um personagem substituindo \;por *. (Você também pode obter muito mais rápido para a contagem de caracteres atual por encontrar o primeiro divisor ao invés de todos eles:10 6?,2>{.),2>{1$\%!}?=},`
Peter Taylor
@ PeterTaylor Obrigado, usando a multiplicação, há um truque muito interessante.
Cristian Lupascu
Há mais um char char com uma variável: substitua .,por :x,e \.@por x\ (espaço em branco é devido a problemas de escape com MD nos comentários) e remova *.
31568 Peter
@ PeterTaylor bom, obrigado! Eu editei meu código.
Cristian Lupascu
4

CJam - 11

1e6,{mp},N*

1e6,- matriz de 0 ... 999999
{mp},- selecione números primos
N*- junte-se a novas linhas

aditsu
fonte
11
O CJam não é mais recente que esta pergunta?
22414 Peter Peter Taylor
@PeterTaylor oh, sim é
aditsu
4

GolfScript, 25 (24) bytes

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

Se o formato de saída especificado na pergunta editada for desconsiderado, um byte poderá ser salvo:

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

Isso imprimirá os números primos como uma matriz (como muitas outras soluções) em vez de uma por linha.

Como funciona

A idéia geral é usar o teorema de Wilson , que afirma que n > 1 é primo se e somente 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.

Benchmarks

Mais rápido que a divisão experimental, mas mais lento que a peneira de Eratóstenes. Veja minha outra resposta .

Dennis
fonte
3

C, 91 88 85 82 81 80 76 72 caracteres

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

O algoritmo é terrivelmente ineficiente, mas, como estamos praticando golfe de código, isso não deve importar.

Gareth
fonte
11
você pode reduzi-lo facilmente: main(i,j,b){for(;i++<1e6;b++&&printf("%d\n",i))for(j=2;j<i;)b=i%j++&&b;}ou alguma idéia como essa (já que eu realmente não a compilei)
Ali1S232
Como é icerto ser 0? Eu acho que, se você fornecer algum argumento, ele falhará. Além disso, acho que jhaverá algum tipo de erro de tipo. Não tenho certeza b.
Erik the Outgolfer
3

Mathematica 25

Supondo que você não saiba o número de primos menor que 10 ^ 6:

Prime@Range@PrimePi[10^6]
DavidC
fonte
3

J, 16 caracteres

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

Sem o requisito de formato de saída, isso pode ser reduzido para 13 caracteres:

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

1]\ apenas pega a matriz de primos de classificação 1, transforma-a em uma matriz de classificação 2 e coloca cada primo em sua própria linha - e, assim, o formato de saída padrão do intérprete transforma a lista de uma linha em um primo por linha.

(#~ f) yé basicamente filter, onde fretorna um booleano para cada elemento em y. i.1e6é o intervalo de números inteiros [0,1000000) e 1&p:é uma função booleana que retorna 1 para números primos.

racionalis
fonte
3

R, 45 43 caracteres

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

Para cada número x de 2 a 1e6, basta imprimi-lo se o número de x mod 2 a x iguais a 0 for menor que 2.

plannapus
fonte
O primeiro número produzido por esse código é 1, mas 1 não é primo.
Sven Hohenstein
@SvenHohenstein Obrigado, corrigido.
plannapus
3

Bash (433643)

Minha tentativa (não tão inteligente) foi usar o fator para fatorar o produto.

factor ${PRODUCT}

Infelizmente, com grandes números, o produto é obviamente enorme. Também levou mais de 12 horas para ser executado. Decidi publicá-lo porque achei que era único.

Aqui está o código completo.

Se fosse primos com menos de seis anos, seria razoável.

  factor 30

Oh, bem, eu tentei.

Kevin Cox
fonte
+1 Esta resposta é verdadeiramente diabólica. Resultado não pré-computado (economiza bastante caracteres) e muito mais terrível de calcular :) É possivelmente também um exemplo que faz com que o otimizado tenha um factordesempenho muito pior do que o algoritmo básico da divisão de teste.
orion 15/05
3

C #, 70

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

Você não verá muito aqui por muito tempo ...

It'sNotALie.
fonte
Existem várias razões pelas quais isso está errado. (1) Você não pode converter implicitamente de a double 1e6para um int, mas inté exigido por Range. (2) O interior Rangedeve levar no máximo n-2termos, caso contrário você testará o n % nque é claramente 0. (3) Você escreve x%nquando quiser n%x. Corrigindo esses problemas, algo como isso funcionará: Enumerable.Range(2,999999).Where(n=>Enumerable.Range(2,n-2).All(x=>n%x!=0))No entanto, isso ainda não gera os números; o requisito era um por linha.
Jeppe Stig Nielsen