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.


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

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.


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

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)'

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.


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.


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


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.


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

8

Ruby 50 41

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

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+$'

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)

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

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.


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


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.


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

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.


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)

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

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=},`

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


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 .



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.


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]

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.


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.


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.


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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.