Sieb des Eratosthenes

  • Allgemein

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von faxe1008.

    Sieb des Eratosthenes

    Hi,

    Ich probiere gerade das Sieb des Eratosthenes in einer Konsole zu verwenden. Das funktioniert so:
    - Lösche die Vielfachen von 2,3,5,7,11
    - Suche ob Vielfache der übrigen Zahlen vorhanden sind und lösche

    Ich habe eine Variante davon geschrieben, allerdings habe ich das Problem, dass ich die Schleife updaten müsste, so dass nur noch die Zahlen durchgegangen werden müssen die übrig sind. Dies würde auch eine deutlich höhere Perfomance bringen.

    C#

    Brainfuck-Quellcode

    1. // Start einlesen
    2. Console.WriteLine("Untergrenze:");
    3. int untergrenze = int.Parse(Console.ReadLine());
    4. // Ende einlesen
    5. Console.WriteLine("Obergrenze:");
    6. int obergrenze = int.Parse(Console.ReadLine());
    7. // Zahlenliste befüllen
    8. IList<int> zahlenliste = new List<int>();
    9. for (int u = untergrenze; u <= obergrenze; u++)
    10. {
    11. zahlenliste.Add(u);
    12. }
    13. Console.WriteLine("--------------------------------------------");
    14. // Filtern
    15. for(int i = 2; i <= zahlenliste.Count - 1; i++)
    16. {
    17. for (int z = 0; z <= zahlenliste.Count - 1; z++)
    18. {
    19. if (zahlenliste.ElementAt(z) % i == 0)
    20. {
    21. if (zahlenliste.ElementAt(z) != i) { zahlenliste.RemoveAt(z); }
    22. }
    23. }
    24. }
    25. for (int w = 0; w <= zahlenliste.Count - 1; w++)
    26. {
    27. Console.WriteLine(zahlenliste.ElementAt(w).ToString());
    28. }
    29. Console.ReadKey();
    30. Console.Clear();


    VB.NET

    VB.NET-Quellcode

    1. ' Start einlesen
    2. Console.WriteLine("Untergrenze:")
    3. Dim untergrenze As Integer = Integer.Parse(Console.ReadLine())
    4. ' Ende einlesen
    5. Console.WriteLine("Obergrenze:")
    6. Dim obergrenze As Integer = Integer.Parse(Console.ReadLine())
    7. ' Zahlenliste befüllen
    8. Dim zahlenliste As IList(Of Integer) = New List(Of Integer)()
    9. For u As Integer = untergrenze To obergrenze
    10. zahlenliste.Add(u)
    11. Next
    12. Console.WriteLine("--------------------------------------------")
    13. ' Filtern
    14. For i As Integer = 2 To zahlenliste.Count - 1
    15. For z As Integer = 0 To zahlenliste.Count - 1
    16. If zahlenliste.ElementAt(z) Mod i = 0 Then
    17. If zahlenliste.ElementAt(z) <> i Then
    18. zahlenliste.RemoveAt(z)
    19. End If
    20. End If
    21. Next
    22. Next
    23. For w As Integer = 0 To zahlenliste.Count - 1
    24. Console.WriteLine(zahlenliste.ElementAt(w).ToString())
    25. Next
    26. Console.ReadKey()
    27. Console.Clear()

    8-) faxe1008 8-)
    Also ich habs mal probiert aber keine Ahnung ob das schnell ist:

    VB.NET-Quellcode

    1. Module Module1
    2. Sub Main()
    3. Do
    4. Console.WriteLine("Zahl eingeben: ")
    5. Dim parse As Integer
    6. Integer.TryParse(Console.ReadLine(), parse)
    7. Console.WriteLine("")
    8. Console.WriteLine("Endzahl eingeben: ")
    9. Dim endzahl As Integer
    10. Integer.TryParse(Console.ReadLine(), endzahl)
    11. Console.WriteLine("")
    12. Console.WriteLine("Primzahlen: ")
    13. For x = parse To endzahl
    14. If x = 2 OrElse x = 3 OrElse x = 5 OrElse x = 7 OrElse x = 11 OrElse ModNull(2, x) AndAlso ModNull(3, x) AndAlso ModNull(5, x) AndAlso ModNull(7, x) AndAlso ModNull(11, x) Then
    15. Console.WriteLine(x)
    16. End If
    17. Next
    18. Loop
    19. Console.ReadLine()
    20. End Sub
    21. Private Function ModNull(ByVal Zahl As Integer, ByVal Schleifenzahl As Integer) As Boolean
    22. Return Math.IEEERemainder(Schleifenzahl, Zahl) <> 0
    23. End Function
    24. End Module

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RushDen“ ()

    Ich seh zwar keine Frage, aber hier ein paar Kritik-/Anregungspunkte:
    a) Beim Sieb des Eratosthenes brauchst du keine Untergrenze, da die Untergrenze IMMER 2 ist.
    b) Warum machst du das so umständlich? Guck dir System.Linq.Enumerable.Range(int, int) an.
    c) Warum For-Schleifen? Linq tut es in dem Fall auch.
    Meine Quick-and-Dirty Lösung:
    coll.Where(item => !check.Any(inner => inner < item & item % inner == 0)),
    coll.Where(Function(item) Not check.Any(Function(inner) item > inner And item Mod inner = 0)).

    Erweitert.
    Copy&Paste-Schutz:
    @faxe1008:: Nicht die Elemente removen, das dauert unendlich lange.
    Trag in die betreffenden Felder eine 0 ein, und alle, die am Ende verschieden von 0 sind, sind Primzahlen.
    Das lässt sich mit Parallel.For herrlich parallelisieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Für diese Aufgabe halte ich die LINQ weder für eine schöne, noch für eine performante Lösung. Es ist einfach nur ein "weil man es kann und es cool aussieht".
    Meine Wahl würde ebenfalls auf @RodFromGermany:s Empfehlung fallen.

    Edit:
    Lol, die Version von AliveDevil benutzt ja nichtmal das Sieb des Eratosthenes. Das ist Primzahlenberechnung mit Modulo - ein ganz anderer Algorithmus (auch viel langsamer).
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nikeee13“ ()

    Ich habe mir Parallel.For angesehen, aber das ist denke ich nicht die Lösung des Problems (nicht die Performance). Das Problem ist eher folgendes (Beispiel):



    1. Alle Zahlen die durch 1 teilbar sind rauswerfen => Macht ja keinen Sinn den jede ist durch 1 teilbar
    2. Alle Zahlen die durch 2 teilbar sind außer der 2 eliminieren:

    3. Nächste stehen gebliebene Zahl ist 3 => alle durch 3 teilbaren Zahlen eliminieren:

    4. Nächste stehen gebliebene Zahl ist 5 => alle durch 5 teilbaren Zahlen eliminieren:


    So das Problem, dass sich hierbei stellt ist, dass die For-Schleife weiterspringen müsste wenn sie zum Beispiel gerade 3 eliminiert hat muss sie ja nicht zu 4 weiterspringen, weil die 4 schon durch die 2 rausgeworfen wurde, sollte sie zur 5 weiter.

    Ich hoffe ich konnte es anschaulich erklären.

    8-) faxe1008 8-)
    Deshalb setzt du die Schrittweite der For-Schleife auch immer auf das, was eliminiert werden soll. Ist die Schleife bei 3, springt er als nächstes zu 6. Gerade das ist ja eine der Optimierungen vom Sieb.
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nikeee13“ ()

    @nikeee13: Ok habe nur ein problem beim Implemetieren:
    1.) Schrittweite inkrementieren
    2.) Liste durchgehen und dann mit der Schrittweite Removen

    VB.NET-Quellcode

    1. int schrittweite = 0;
    2. for (int u = 0; u <= zahlenliste.Count - 1; u++)
    3. {
    4. schrittweite = u;
    5. for (int toremove = 0; toremove <= zahlenliste.Count - 1; toremove = schrittweite + toremove)
    6. {
    7. zahlenliste.RemoveAt(toremove);
    8. }
    9. }


    Das funktioniert leider nicht. Was passt hier nicht?

    8-) faxe1008 8-)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „faxe1008“ ()

    Besser wäre es, wenn du die rausgeschmissenen Zahlen einfach auf 0 bzw. False/True setzt (wie @RodFromGermany: schon schrieb). So veränderst du nicht jedes mal den Listenindex.
    Auf Wikipedia gibt es einen Pseudocode, den du praktisch nur in C# umwandeln musst.

    Quellcode

    1. const N = 10000
    2. var gestrichen: array [2..N] of boolean
    3. // Initialisierung des Primzahlfeldes
    4. // Alle Zahlen im Feld sind zu Beginn nicht gestrichen
    5. for i = 2 to N do
    6. gestrichen[i] = false
    7. end
    8. for i = 2 to N do
    9. if not gestrichen[i] then
    10. // i ist prim, gib i aus
    11. print i; ", ";
    12. // und streiche seine Vielfachen, beginnend mit i*i
    13. // (denn k*i mit k<i wurde schon als Vielfaches von k gestrichen)
    14. for j = i*i to N step i do
    15. gestrichen[j] = true
    16. end
    17. end if
    18. end

    Du brauchst in der Liste ja auch nicht die Zahlen haben, denn du hast ja den Index, aus dem die Zahlen folgen. Deshalb arbeitet man hier am besten mit einem Boolean-Array. Dort "streichst" du die einzelnen Zahlen, indem du beim Array den Wer am Index der Zahl auf False/True setzt. Am Ende musst du nur alle ausgeben, die nicht False/True sind.
    Von meinem iPhone gesendet