Tamiz de Sundaram (para encontrar números primos)

13

El reto

Implemente el tamiz Sundaram para encontrar los números primos a continuación n. Tome un entero de entrada n, y envíe los números primos a continuación n. Puede suponer que nsiempre será menor o igual a un millón.


Tamiz

  1. Comience con una lista de los enteros de 1a n.

  2. Elimine todos los números que están en la forma i + j + 2ijdonde:

    • iy json menos que n. jsiempre es mayor o igual que i, que es mayor o igual que 1.

    • i + j + 2ij es menor o igual que n

  3. Multiplica los números restantes por 2y suma 1.

Esto producirá todos los números primos (excepto 2, que deben incluirse en su salida) menos que 2n + 2.


Aquí hay una animación del tamiz que se usa para encontrar primos a continuación 202.


Salida

Su salida debe ser cada número entero primo ≤ n(en orden ascendente) seguido de una nueva línea:

2
3
5

Donde nes 5.


Ejemplos

> 10
2
3
5
7

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

Las entradas se denotan por >.

Puertas de Zach
fuente
Su ejemplo con n=30falta 29 en la salida.
isaacg
55
Un problema con los desafíos que requieren usar un método específico es que no está claro qué modificaciones se pueden hacer. Por ejemplo, su descripción solo se verifica (i,j)con i<=j, pero el resultado no cambia si ignoramos este requisito. ¿Podemos hacerlo para guardar bytes?
xnor
Nunca dije que tenías que comprobar si i <= j . Es solo parte de cómo funciona el tamiz. Entonces sí, puede omitir el i <= jen su código. @xnor
Zach Gates
2
¿Cuánta libertad tenemos aquí? El tamiz es equivalente a seleccionar todos los números impares (porque los resultados son de la forma 2n+1) que no son de la forma 2(i + j + 2ij)+1: ¿podemos probar esta propiedad directamente en los números primos potenciales o nuestro código tiene que hacer los tiempos 2 más 1 en algún momento? ?
Martin Ender
1
Estoy un poco confundido por lo que nhay en todo el asunto. En la descripción del método, dice que generará todos los primos hasta 2 * n + 2. Pero en la descripción de entrada / salida, dice que la entrada es n, y la salida se prepara hasta n. Entonces, ¿se supone que debemos aplicar el método para generar todos los primos 2 * n + 2y luego eliminar los más grandes que npara la salida? ¿O deberíamos calcular nen la descripción del método a partir de la entrada n?
Reto Koradi

Respuestas:

7

Pyth, 23 bytes

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

Demostración

Realmente solo implementa el algoritmo como se indica.

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

Cómo funciona: [i+j+2*i*j|j<-r,i<-r]son todos los i+j+2ijque se eliminan ( \\) de [1..n]. Escale 2x+1y conviértalos en una cadena ( show). Únete con NL ( unlines).

nimi
fuente
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)}

Una función anónima; toma n como argumento e imprime el resultado en stdout.

Ben
fuente
1

JavaScript (ES7), 107 105 bytes

¡Las comprensiones de matriz son increíbles! Pero me pregunto por qué JS no tiene sintaxis de rango (por ejemplo [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]}

Esto se probó con éxito en Firefox 40. Desglose:

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
}

Solución alternativa, compatible con 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)}

Sugerencias bienvenidas!

ETHproductions
fuente
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);

Y en una forma legible

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
fuente
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 números más grandes, se puede utilizar el tipo de datos con amplio rango. No necesitamos iterar para Níndices completos N/2es suficiente.

Para entender correctamente el siguiente es el 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
fuente
1
N>=2-> N>1? A[i]==0-> A[i]<1?
lirtosiast
@ThomasKwa Sí, tienes razón. Gracias.
CoderCroc
0

CJam, 35 bytes

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

Pruébalo en línea

Esto parece algo largo en relación con la solución Pyth de Isaac, pero es ... lo que tengo.

Explicación:

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
fuente
0

Perl 6 , 96 bytes

Si sigo estrictamente la descripción, el más corto que logré obtener es 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)
}

Si pudiera hacer la 2n + 1inicialización de la matriz, pre-insertar 2y limitar eso solo a los valores menores o iguales a n; Se puede reducir a 84 bytes.

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

Si también ignoro que jse supone que es al menos i, puedo reducirlo a 82 bytes.

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

Ejemplo 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
fuente
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";

Versión en línea

Jörg Hülsermann
fuente
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]]

Pruébalo en línea!

No es un gran desafío en términos de golf, pero solo tuve que hacerlo por el nombre. :)

sundar - Restablecer a Monica
fuente