Sieb von Sundaram (zum Finden von Primzahlen)


13

Die Herausforderung

Implementieren Sie das Sundaram-Sieb, um die Primzahlen unten zu finden n. Nehmen Sie eine Ganzzahl nund geben Sie die folgenden Primzahlen aus n. Sie können davon ausgehen, dass dies nimmer weniger als oder gleich einer Million sein wird.


Sieb

  1. Beginnen Sie mit einer Liste der Ganzzahlen von 1bis n.

  2. Entfernen Sie alle Zahlen in dem Formular, i + j + 2ijin dem:

    • iund jsind kleiner als n. jist immer größer als oder gleich i, was größer als oder gleich ist 1.

    • i + j + 2ij ist kleiner oder gleich n

  3. Multiplizieren Sie die verbleibenden Zahlen mit 2und addieren Sie 1.

Dies ergibt alle Primzahlen (mit Ausnahme derjenigen 2, die in Ihrer Ausgabe enthalten sein sollten) kleiner als 2n + 2.


Hier ist eine Animation des Siebs, mit dem die Primzahlen unten ermittelt werden 202.


Ausgabe

Ihre Ausgabe sollte jede Primzahl ≤ n(in aufsteigender Reihenfolge) sein, gefolgt von einer neuen Zeile:

2
3
5

Wo nist 5.


Beispiele

> 10
2
3
5
7

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

Eingänge sind mit gekennzeichnet >.


Ihr Beispiel mit n=30fehlt 29 in der Ausgabe.
Isaacg

5
Ein Problem bei Herausforderungen, die die Verwendung einer bestimmten Methode erfordern, besteht darin, dass nicht klar ist, welche Änderungen vorgenommen werden können. Zum Beispiel überprüft Ihre Beschreibung nur (i,j)mit i<=j, aber das Ergebnis ändert sich nicht, wenn wir diese Anforderung ignorieren. Können wir das tun, um Bytes zu sparen?
30.

Ich habe nie gesagt, dass Sie überprüfen müssen, ob i <= j. Es ist nur ein Teil der Funktionsweise des Siebs. Also ja, Sie können das i <= jin Ihrem Code weglassen. @xnor
Zach Gates

2
Wie viel Spielraum haben wir hier? Das Sieb ist äquivalent alle ungeraden Zahlen auf der Auswahl (weil die Ergebnisse des Formulars sind 2n+1) , die nicht von der Form ist 2(i + j + 2ij)+1- können wir dieses Objekt direkt über die möglichen Primzahlen testen oder auch unseren Code haben die mal 2 plus 1 an einem gewissen Punkt zu tun ?
Martin Ender

1
Ich bin ein bisschen verwirrt von dem, was nin der ganzen Sache steckt. In der Methodenbeschreibung wird angegeben, dass alle Primzahlen bis generiert werden 2 * n + 2. In der Eingabe- / Ausgabebeschreibung heißt es jedoch, dass die Eingabe nund die Ausgabe alle Primzahlen sind n. Sollen wir also die Methode anwenden, um alle Primzahlen bis zu zu generieren 2 * n + 2und dann diejenigen fallen zu lassen, die größer sind als nfür die Ausgabe? Oder sollen wir das nin der Methodenbeschreibung aus der Eingabe berechnen n?
Reto Koradi

Antworten:



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]

So funktioniert es: [i+j+2*i*j|j<-r,i<-r]Sind alle i+j+2ijdie entfernt werden ( \\) aus [1..n]. Skaliere zu 2x+1und verwandle sie in einen String ( show). Join with NL ( unlines).


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

Eine anonyme Funktion; Nimmt n als Argument und gibt das Ergebnis an stdout aus.


1

JavaScript (ES7), 107 - 105 Byte

Das Array-Verständnis ist fantastisch! Aber ich frage mich, warum JS keine Bereichssyntax hat (zB [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]}

Dies wurde erfolgreich in Firefox 40 getestet. Aufschlüsselung:

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
}

Alternative, ES6-freundliche Lösung (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)}

Vorschläge willkommen!


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

Und in lesbarer Form

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

Für eine größere Anzahl kann ein Datentyp mit großem Bereich verwendet werden. Es ist nicht ausreichend, ganze NIndizes zu iterieren N/2.

Richtig zu verstehen, ist die äquivalente Methode.

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 Ja du hast recht. Vielen Dank.
CoderCroc

0

CJam, 35 Bytes

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

Probieren Sie es online aus

Dies scheint im Vergleich zu isaacgs Pyth-Lösung etwas langwierig zu sein, aber es ist ... was ich habe.

Erläuterung:

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 Bytes

Wenn ich mich strikt an die Beschreibung halte, ist der kürzeste, den ich bekommen habe, 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)
}

Wenn ich die 2n + 1on-Initialisierung des Arrays durchführen könnte, das vorab einfügen 2und das auf nur die Werte begrenzen könnte, die kleiner oder gleich sind n; es kann auf 84 Bytes reduziert werden.

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

Wenn ich das jzumindest auch ignoriere, ikann ich es auf 82 Bytes reduzieren.

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

Beispielverwendung:

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)


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.