Setaccio di Sundaram (per trovare i numeri primi)


13

La sfida

Implementa il setaccio Sundaram per trovare i numeri primi di seguito n. Prendi un numero intero di input ne genera i numeri primi di seguito n. Puoi presumere che nsarà sempre inferiore o uguale a un milione.


Setaccio

  1. Inizia con un elenco di numeri interi da 1a n.

  2. Rimuovi tutti i numeri che si trovano nel modulo in i + j + 2ijcui:

    • ie jsono inferiori a n. jè sempre maggiore o uguale a i, che è maggiore o uguale a 1.

    • i + j + 2ij è inferiore o uguale a n

  3. Moltiplica i numeri rimanenti per 2e aggiungi 1.

Ciò produrrà tutti i numeri primi (tranne 2, che dovrebbero essere inclusi nell'output) in meno di 2n + 2.


Ecco un'animazione del setaccio utilizzato per trovare i numeri primi di seguito 202.


Produzione

L'output dovrebbe essere ogni numero intero primo ≤ n(in ordine crescente) seguito da una nuova riga:

2
3
5

Dove nsi trova 5.


Esempi

> 10
2
3
5
7

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

Gli ingressi sono indicati da >.


Nell'esempio n=30manca 29 nell'output.
isaacg,

5
Un problema con le sfide che richiedono di utilizzare un metodo specifico è che non è chiaro quali modifiche si possano apportare. Ad esempio, la descrizione viene verificata solo (i,j)con i<=j, ma il risultato non cambia se ignoriamo questo requisito. Possiamo farlo per salvare byte?
xnor

Non ho mai detto che dovevi controllare se i <= j. Fa solo parte di come funziona il setaccio. Quindi sì, puoi tralasciare il i <= jcodice. @xnor
Zach Gates,

2
Quanto margine di manovra abbiamo qui? Il setaccio equivale a selezionare tutti i numeri dispari (perché i risultati sono del modulo 2n+1) che non sono del modulo 2(i + j + 2ij)+1- possiamo testare questa proprietà direttamente sui numeri primi potenziali o il nostro codice deve fare i tempi 2 più 1 ad un certo punto ?
Martin Ender,

1
Sono un po 'confuso da ciò che nè nel complesso. Nella descrizione del metodo, dice che genererà tutti i numeri primi fino a 2 * n + 2. Ma nella descrizione input / output, dice che l'input è n, e l'output è tutto pronto n. Quindi dovremmo applicare il metodo per generare fino a tutti i numeri primi 2 * n + 2e quindi eliminare quelli più grandi rispetto nall'output? O dovremmo calcolare la ndescrizione del metodo dall'input n?
Reto Koradi,

Risposte:



3

Haskell, 93 90 byte

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]

Come funziona: [i+j+2*i*j|j<-r,i<-r]sono tutti quelli i+j+2ijche vengono rimossi ( \\) da [1..n]. Scala a 2x+1e trasformali in una stringa ( show). Unisciti a NL ( unlines).


1

Scala, 115 124 122 115 114 byte

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 funzione anonima; prende n come argomento e stampa il risultato su stdout.


1

JavaScript (ES7), 107 105 byte

Le comprensioni dell'array sono fantastiche! Ma mi chiedo perché JS non abbia sintassi del range (ad es. [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]}

Questo è stato testato correttamente in Firefox 40. Ripartizione:

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
}

Soluzione alternativa compatibile con ES6 (111 byte):

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

Suggerimenti benvenuti!


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 in una forma leggibile

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.

0

Java8: 168 165 byte

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

Per numeri più grandi è possibile utilizzare un tipo di dati con un ampio intervallo. Non è necessario iterare per interi Nindici N/2è sufficiente.

Per capire correttamente, seguire è il metodo 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);
}

1
N>=2-> N>1? A[i]==0-> A[i]<1?
lirtosiast

@ThomasKwa Sì, hai ragione. Grazie.
CoderCroc

0

CJam, 35 byte

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

Provalo online

Questo sembra un po 'lungo rispetto alla soluzione Pyth di isaacg, ma è ... quello che ho.

Spiegazione:

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.

0

Perl 6 , 96 byte

Se seguo rigorosamente la descrizione il più breve che sono riuscito a ottenere è di 96 byte.

->\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 potessi fare l' 2n + 1inizializzazione all'array, pre-inserire 2e limitare quello solo ai valori inferiori o uguali a n; può essere ridotto a 84 byte.

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

Se ignoro anche quello che jdovrebbe essere almeno i, posso ridurlo a 82 byte.

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

Esempio di utilizzo:

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)


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.