Peneira de Sundaram (para encontrar números primos)

13

O desafio

Implemente a peneira Sundaram para encontrar os números primos abaixo n. Pegue um número inteiro de entrada ne dê os números primos abaixo n. Você pode assumir que nsempre será menor ou igual a um milhão.


Peneira

  1. Comece com uma lista dos números inteiros de 1até n.

  2. Remova todos os números que estão no formulário em i + j + 2ijque:

    • ie jsão menores que n. jé sempre maior que ou igual a i, que é maior que ou igual a 1.

    • i + j + 2ij é menor ou igual a n

  3. Multiplique os números restantes por 2e adicione 1.

Isso produzirá todos os números primos (exceto os 2que devem ser incluídos na sua saída) inferiores a 2n + 2.


Aqui está uma animação da peneira usada para encontrar os números primos abaixo 202.


Resultado

Sua saída deve ser todo número inteiro primo ≤ n(em ordem crescente) seguido por uma nova linha:

2
3
5

Onde né 5.


Exemplos

> 10
2
3
5
7

> 30
2
3
5
7
11
13
17
19
23
29

As entradas são indicadas por >.

Zach Gates
fonte
Seu exemplo com n=30está faltando 29 na saída.
Isaacg
5
Um problema com os desafios que pedem para usar um método específico é que não está claro quais modificações podem ser feitas. Por exemplo, sua descrição verifica apenas (i,j)com i<=j, mas o resultado não muda se ignorarmos esse requisito. Podemos fazer isso para salvar bytes?
xnor
Eu nunca disse que você tinha que verificar se i <= j. É apenas parte de como a peneira funciona. Então, sim, você pode deixar de fora o i <= jcódigo. @xnor
Zach Gates
2
Quanta margem de manobra temos aqui? A peneira é equivalente a selecionar todos os números ímpares (porque os resultados são da forma 2n+1) que não são da forma 2(i + j + 2ij)+1- podemos testar essa propriedade diretamente nos primos em potencial ou nosso código precisa fazer os tempos 2 mais 1 em algum momento ?
Martin Ender
1
Estou um pouco confuso com o que nestá na coisa toda. Na descrição do método, ele diz que irá gerar todos os números primos até 2 * n + 2. Mas na descrição de entrada / saída, diz que a entrada é ne a saída é iniciada até n. Então, devemos aplicar o método para gerar todos os números primos até 2 * n + 2, e depois largar os que forem maiores do que npara a saída? Ou devemos calcular a ndescrição do método a partir da entrada n?
Reto Koradi

Respostas:

7

Pitão, 23 bytes

2j@JSQmhyd-Jm+sdy*Fd^J2

Demonstração

Realmente apenas implementa o algoritmo como dado.

isaacg
fonte
3

Haskell, 93 90 bytes

import Data.List
g n=unlines[show$2*x+1|r<-[[1..n]],x<-2:(r\\[i+j+2*i*j|j<-r,i<-r]),2*x<n]

Como funciona: [i+j+2*i*j|j<-r,i<-r]são todos os i+j+2ijquais são removidos ( \\) de [1..n]. Dimensione 2x+1e transforme-os em uma string ( show). Junte-se a NL ( unlines).

nimi
fonte
1

Scala, 115 124 122 115 114 bytes

n=>{println(2);for{m<-1 to n;if !(for{j<-1 to n;i<-1 to j}yield i+j+2*i*j).contains(m);o=2*m+1;if o<=n}println(o)}

Uma função anônima; toma n como argumento e imprime o resultado em stdout.

Ben
fonte
1

JavaScript (ES7), 107 105 bytes

Compreensões de matriz são impressionantes! Mas eu me pergunto por que JS não tem sintaxe de alcance (por exemplo [1..n]) ...

n=>{for(a=[i=1];i<n;a[i++]=i);for(i=0;i++<n;)for(j=0;j<n;a[i+j+++2*i*j]=0);return[for(i of a)if(i)i*2+1]}

Isso foi testado com sucesso no Firefox 40. Avaria:

n=>{
  for(a=[i=1];i<n;a[i++]=i); // fill a list with 1..n
  for(i=0;i++<n;)            // for each integer i in 0..n
    for(j=0;j<n;)            //   for each integer j in 0..n
      a[i+j+++2*i*j-1]=0;    //     set the corresponding item of the list to 0
  return[for(i of a)         // filter the list by:
          if(i)              //   item != 0 AND item != undefined
           i*2+1]            // and return each result * 2 + 1
}

Solução alternativa compatível com ES6 (111 bytes):

n=>{for(a=[i=1];i<n;a[i++]=i);for(i=0;i++<n;)for(j=0;j<n;a[i+j+++2*i*j]=0);return a.filter(x=>x).map(x=>x*2+1)}

Sugestões são bem-vindas!

ETHproductions
fonte
0

MATLAB, 98

n=1:input('');m=n;for p=m for i=1:p j=i:p;for k=i+j+2*i*j n(n==k)=[];end;end;end;disp(2*n'+1);

E de forma legível

n=1:input(''); %Ask for the input number (e.g. 100) and form a range
m=n; %Back up the range as we will be editing 'n', but need 'm' as a loop list
for p=m %For each number between 1 and n inclusive
    for i=1:p %'i' is all numbers greater than or equal to 1 up to p
        j=i:p; %'j' is all numbers greater than or equal to i up to p
        for k=i+j+2*i*j %Calculate the numbers to remove, and loop through them
            n(n==k)=[]; %Remove that value from the 'n' array
        end
    end
end
disp([2;2*n'+1]); %An display the list including the number 2 seperated by a new line.
Tom Carpenter
fonte
0

Java8: 168 165 bytes

N->{int[]A=new int[N*N];int i=1,j;N=N/2;for(;i<N;i++)for(j=i;j<N;)A[i+j+2*i*j++]=1;System.out.println(N>1?2:\"\");for(i=1;i<N;i++)if(A[i]<1)System.out.println(2*i+1);}

Para um número maior, é possível usar o tipo de dados com ampla faixa. Não precisamos iterar, pois Níndices inteiros N/2são suficientes.

Entender adequadamente o seguinte é o método equivalente.

static void findPrimeSundar(int N){
    int[] A = new int[N*N];
    int i=1,j;
    N=N/2;
    for(;i<N;i++)
      for(j=i;j<N;)
        A[i+j+2*i*j++]=1;
    System.out.println(N>1?2:"");
    for(i=1;i<N;i++)
        if(A[i]<1)System.out.println(2*i+ 1);
}
CoderCroc
fonte
1
N>=2-> N>1? A[i]==0-> A[i]<1?
Lirtosiast
@ThomasKwa Sim, você está certo. Obrigado.
CoderCroc
0

CJam, 35 bytes

2li:V,:)__2m*{_:+\:*2*+}%m2f*:)&+N*

Experimente online

Isso parece um pouco demorado em relação à solução Pyth de isaacg, mas é ... o que eu tenho.

Explicação:

2       Push a 2, will be part of final output.
li      Get input and convert to integer n.
:V      Save in variable V for later use.
,       Generate list [0 ... n-1].
:)      Increment list elements to get list [1 ... n].
__      Create two copies, one for sieve, and for clamping results.
2m*     Cartesian power, generating all i,k pairs.
{       Loop over all i,j pairs.
  _     Copy pair.
  :+    Calculate sum i + j.
  \     Swap copy of pair to top.
  :*    Calculate product i * j.
  2*    Multiply by 2, to get 2 * i * j.
  +     Add both values, to get i + j + 2 * i * j.
}%      End loop over all i,j pairs.
m       Sieve operation, remove the calculated values from the list of all values.
2f*     Multiply the remaining values by 2...
:)      ... and add 1 to the. We now have the list of all primes up to 2 * n + 2.
&       Intersect with [1 ... n] list, because output is only values <= n.
+       Concatenate with the 2 we pushed at the start.
N*      Join with newlines.
Reto Koradi
fonte
0

Perl 6 , 96 bytes

Se eu seguir rigorosamente a descrição, o menor que consegui obter será de 96 bytes.

->\n {$_=@=1..n;for 1..n {for $^i..n {.[$i+$^j+2*$i*$j-1]=0}};2,|.[0..n].map(* *2+1).grep(3..n)}
->\n {
  $_=@=1..n; # initialize array
  for 1..n { # $i
    for $^i..n { # $j
      .[$i+$^j+2*$i*$j-1]=0 # remove value
    }
  };
  2,|.[0..n].map(* *2+1).grep(3..n)
}

Se eu pudesse fazer a 2n + 1inicialização da matriz, inserindo 2e limitando isso apenas aos valores menores ou iguais a n; pode ser reduzido para 84 bytes.

->\n {$_=@=2,{++$*2+1}...^*>n;for 1..n {for $^i..n {.[$i+$^j+2*$i*$j]=$}};.grep(?*)}

Se eu também ignorar o que jdeveria ser pelo menos i, posso reduzi-lo para 82 bytes.

->\n {$_=@=2,{++$*2+1}...^*>n;for 1..n X 1..n ->(\i,\j){.[i+j+2*i*j]=$};.grep(?*)}

Exemplo de uso:

my $code = ->\n {...} # insert one of the lambdas from above

say $code(30).join(',');
# 2,3,5,7,11,13,17,19,23,29

my &code = $code;
say code 11;
# (2 3 5 7 11)
Brad Gilbert b2gills
fonte
0

PHP, 126 bytes

$r=range(1,$n=$argn/2-1);for(;++$i**2<=$n;)for($j=$i;$n>=$d=$j+$i+2*$i*$j++;)unset($r[$d-1]);foreach($r as$v)echo 1+2*$v."\n";

Versão Online

Jörg Hülsermann
fonte
0

Julia 0.6 , 65 bytes

n->[2;(p=setdiff(1:n,[i+j+2i*j for i=1:n for j=i:n])*2+1)[p.<=n]]

Experimente online!

Não é um grande desafio em termos de golfe, mas eu apenas tive que fazê-lo pelo nome. :)

sundar - Restabelecer Monica
fonte