Most efficient code for the first 10000 prime numbers?

前端 未结 30 1399
日久生厌
日久生厌 2020-11-29 19:09

I want to print the first 10000 prime numbers. Can anyone give me the most efficient code for this? Clarifications:

  1. It does not matter if your code is ineffici
相关标签:
30条回答
  • 2020-11-29 19:33

    Here is my VB 2008 code, which finds all primes <10,000,000 in 1 min 27 secs on my work laptop. It skips even numbers and only looks for primes that are < the sqrt of the test number. It is only designed to find primes from 0 to a sentinal value.

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 
    Button1.Click
    
        Dim TestNum As Integer
        Dim X As Integer
        Dim Z As Integer
        Dim TM As Single
        Dim TS As Single
        Dim TMS As Single
        Dim UnPrime As Boolean
        Dim Sentinal As Integer
        Button1.Text = "Thinking"
        Button1.Refresh()
        Sentinal = Val(SentinalTxt.Text)
        UnPrime = True
        Primes(0) = 2
        Primes(1) = 3
        Z = 1
        TM = TimeOfDay.Minute
        TS = TimeOfDay.Second
        TMS = TimeOfDay.Millisecond
        For TestNum = 5 To Sentinal Step 2
            Do While Primes(X) <> 0 And UnPrime And Primes(X) ^ 2 <= TestNum
                If Int(TestNum / Primes(X)) - (TestNum / Primes(X)) = 0 Then
                    UnPrime = False
                End If
                X = X + 1
    
            Loop
            If UnPrime = True Then
                X = X + 1
                Z = Z + 1
                Primes(Z) = TestNum
            End If
            UnPrime = True
            X = 0
        Next
        Button1.Text = "Finished with " & Z
        TM = TimeOfDay.Minute - TM
        TS = TimeOfDay.Second - TS
        TMS = TimeOfDay.Millisecond - TMS
        ShowTime.Text = TM & ":" & TS & ":" & TMS
    End Sub
    
    0 讨论(0)
  • 2020-11-29 19:36

    I spend some time writing a program calculating a lot of primes and this is the code I'm used to calculate a text file containing the first 1.000.000.000 primes. It's in German, but the interesting part is the method calcPrimes(). The primes are stored in an array called Primzahlen. I recommend a 64bit CPU because the calculations are with 64bit integers.

    import java.io.*;
    class Primzahlengenerator {
        long[] Primzahlen;
        int LastUnknown = 2;
        public static void main(String[] args)  {
            Primzahlengenerator Generator = new Primzahlengenerator();
            switch(args.length) {
                case 0:  //Wenn keine Argumente übergeben worden:
                    Generator.printHelp(); //Hilfe ausgeben
                    return; //Durchfallen verhindern
                case 1:
                    try {
                        Generator.Primzahlen = new long[Integer.decode(args[0]).intValue()];
                    }
                    catch (NumberFormatException e) {
                        System.out.println("Das erste Argument muss eine Zahl sein, und nicht als Wort z.B. \"Tausend\", sondern in Ziffern z.B. \"1000\" ausgedrückt werden.");//Hinweis, wie man die Argumente angeben muss ausgeben
                        Generator.printHelp();                    //Generelle Hilfe ausgeben
                        return;
                    }
                    break;//dutchfallen verhindern
    
                case 2:
                    switch (args[1]) {
                        case "-l":
                            System.out.println("Sie müsen auch eine Datei angeben!"); //Hilfemitteilung ausgeben
                            Generator.printHelp();                                    //Generelle Hilfe ausgeben
                            return;
                    }
                    break;//durchfallen verhindern
                case 3:
                    try {
                        Generator.Primzahlen = new long[Integer.decode(args[0]).intValue()];
                    }
                    catch (NumberFormatException e) {
                        System.out.println("Das erste Argument muss eine Zahl sein, und nicht als Wort z.B. \"Tausend\", sondern in Ziffern z.B. \"1000\" ausgedrückt werden.");//Hinweis, wie man die Argumente angeben muss ausgeben
                        Generator.printHelp();                      //Generelle Hilfe ausgeben
                        return;
                    }
                    switch(args[1]) {
                        case "-l":
                            Generator.loadFromFile(args[2]);//Datei Namens des Inhalts von Argument 3 lesen, falls Argument 2 = "-l" ist
                            break;
                        default:
                            Generator.printHelp();
                            break;
                    }
                    break;
                default:
                    Generator.printHelp();
                    return;
            }
            Generator.calcPrims();
        }
        void printHelp() {
            System.out.println("Sie müssen als erstes Argument angeben, die wieviel ersten Primzahlen sie berechnen wollen.");   //Anleitung wie man das Programm mit Argumenten füttern muss
            System.out.println("Als zweites Argument können sie \"-l\" wählen, worauf die Datei, aus der die Primzahlen geladen werden sollen,");
            System.out.println("folgen muss. Sie muss genauso aufgebaut sein, wie eine Datei Primzahlen.txt, die durch den Aufruf \"java Primzahlengenerator 1000 > Primzahlen.txt\" entsteht.");
        }
        void loadFromFile(String File) {
            // System.out.println("Lese Datei namens: \"" + File + "\"");
            try{
                int x = 0;
                BufferedReader in = new BufferedReader(new FileReader(File));
                String line;
                while((line = in.readLine()) != null) {
                    Primzahlen[x] = new Long(line).longValue();
                    x++;
                }
                LastUnknown = x;
            } catch(FileNotFoundException ex) {
                System.out.println("Die angegebene Datei existiert nicht. Bitte geben sie eine existierende Datei an.");
            } catch(IOException ex) {
                System.err.println(ex);
            } catch(ArrayIndexOutOfBoundsException ex) {
                System.out.println("Die Datei enthält mehr Primzahlen als der reservierte Speicherbereich aufnehmen kann. Bitte geben sie als erstes Argument eine größere Zahl an,");
                System.out.println("damit alle in der Datei enthaltenen Primzahlen aufgenommen werden können.");
                }
            /* for(long prim : Primzahlen) {
                System.out.println("" + prim);
            } */
            //Hier soll code stehen, der von der Datei mit angegebenem Namen ( Wie diese aussieht einfach durch angeben von folgendem in cmd rausfinden:
            //java Primzahlengenerator 1000 > 1000Primzahlen.txt
            //da kommt ne textdatei, die die primzahlen enthält. mit Long.decode(String ziffern).longValue();
            //erhält man das was an der entsprechenden stelle in das array soll. die erste zeile soll in [0] , die zweite zeile in [1] und so weiter.
            //falls im arry der platz aus geht(die exception kenn ich grad nich, aber mach mal:
            //int[] foo = { 1, 2, 3};
            //int bar = foo[4];
            //dann kriegst ne exception, das ist die gleiche die man kriegt, wenn im arry der platzt aus geht.
        }
        void calcPrims() {
            int PrimzahlNummer = LastUnknown;
            // System.out.println("LAstUnknown ist: " + LastUnknown);
            Primzahlen[0] = 2;
            Primzahlen[1] = 3;
            long AktuelleZahl = Primzahlen[PrimzahlNummer - 1];
            boolean IstPrimzahl;
            // System.out.println("2");
            // System.out.println("3");
            int Limit = Primzahlen.length;
            while(PrimzahlNummer < Limit) {
                IstPrimzahl = true;
                double WurzelDerAktuellenZahl = java.lang.Math.sqrt(AktuelleZahl);
                for(int i = 1;i < PrimzahlNummer;i++) {
                    if(AktuelleZahl % Primzahlen[i] == 0) {
                        IstPrimzahl = false;
                        break;
                    }
                    if(Primzahlen[i] > WurzelDerAktuellenZahl) break;
                }
                if(IstPrimzahl) {
                    Primzahlen[PrimzahlNummer] = AktuelleZahl;
                    PrimzahlNummer++;
                    // System.out.println("" + AktuelleZahl);
                }
                AktuelleZahl = AktuelleZahl + 2;
            }
            for(long prim : Primzahlen) {
                System.out.println("" + prim);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:37

    Using Sieve of Eratosthenes, computation is quite faster compare to "known-wide" prime numbers algorithm.

    By using pseudocode from it's wiki (https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes), I be able to have the solution on C#.

    /// Get non-negative prime numbers until n using Sieve of Eratosthenes.
    public int[] GetPrimes(int n) {
        if (n <= 1) {
            return new int[] { };
        }
    
        var mark = new bool[n];
        for(var i = 2; i < n; i++) {
            mark[i] = true;
        }
    
        for (var i = 2; i < Math.Sqrt(n); i++) {
            if (mark[i]) {
                for (var j = (i * i); j < n; j += i) {
                    mark[j] = false;
                }
            }
        }
    
        var primes = new List<int>();
        for(var i = 3; i < n; i++) {
            if (mark[i]) {
                primes.Add(i);
            }
        }
    
        return primes.ToArray();
    }
    

    GetPrimes(100000000) takes 2s and 330ms.

    NOTE: Value might vary depend on Hardware Specifications.

    0 讨论(0)
  • 2020-11-29 19:38

    In Haskell, we can write down almost word for word the mathematical definition of the sieve of Eratosthenes, "primes are natural numbers above 1 without any composite numbers, where composites are found by enumeration of each prime's multiples":

    import Data.List.Ordered (minus, union)
    
    primes = 2 : minus [3..] (foldr (\p r -> p*p : union [p*p+p, p*p+2*p..] r)
                                    [] primes)
    

    primes !! 10000 is near-instantaneous.

    References:

    • Sieve of Eratosthenes
    • Richard Bird's sieve (see pp. 10,11)
    • minus, union

    The above code is easily tweaked into working on odds only, primes = 2 : 3 : minus [5,7..] (foldr (\p r -> p*p : union [p*p+2*p, p*p+4*p..] r) [] (tail primes)). Time complexity is much improved (to just about a log factor above optimal) by folding in a tree-like structure, and space complexity is drastically improved by multistage primes production, in

    primes = 2 : _Y ( (3:) . sieve 5 . _U . map (\p -> [p*p, p*p+2*p..]) )
      where
        _Y g = g (_Y g)                        -- non-sharing fixpoint combinator
        _U ((x:xs):t) = x : (union xs . _U . pairs) t       -- ~= nub.sort.concat
        pairs    (xs:ys:t)  = union xs ys : pairs t
        sieve k s@(x:xs) | k < x      = k : sieve (k+2) s   -- ~= [k,k+2..]\\s,
                         | otherwise  =     sieve (k+2) xs  --   when s⊂[k,k+2..]
    

    (In Haskell the parentheses are used for grouping, a function call is signified just by juxtaposition, (:) is a cons operator for lists, and (.) is a functional composition operator: (f . g) x = (\y -> f (g y)) x = f (g x)).

    0 讨论(0)
  • 2020-11-29 19:40

    I recommend a sieve, either the Sieve of Eratosthenes or the Sieve of Atkin.

    The sieve or Eratosthenes is probably the most intuitive method of finding a list of primes. Basically you:

    1. Write down a list of numbers from 2 to whatever limit you want, let's say 1000.
    2. Take the first number that isn't crossed off (for the first iteration this is 2) and cross off all multiples of that number from the list.
    3. Repeat step 2 until you reach the end of the list. All the numbers that aren't crossed off are prime.

    Obviously there are quite a few optimizations that can be done to make this algorithm work faster, but this is the basic idea.

    The sieve of Atkin uses a similar approach, but unfortunately I don't know enough about it to explain it to you. But I do know that the algorithm I linked takes 8 seconds to figure out all the primes up to 1000000000 on an ancient Pentium II-350

    Sieve of Eratosthenes Source Code: http://web.archive.org/web/20140705111241/http://primes.utm.edu/links/programs/sieves/Eratosthenes/C_source_code/

    Sieve of Atkin Source Code: http://cr.yp.to/primegen.html

    0 讨论(0)
  • 2020-11-29 19:41

    Adapting and following on from GateKiller, here's the final version that I've used.

        public IEnumerable<long> PrimeNumbers(long number)
        {
            List<long> primes = new List<long>();
            for (int i = 2; primes.Count < number; i++)
            {
                bool divisible = false;
    
                foreach (int num in primes)
                {
                    if (i % num == 0)
                        divisible = true;
    
                    if (num > Math.Sqrt(i))
                        break;
                }
    
                if (divisible == false)
                    primes.Add(i);
            }
            return primes;
        }
    

    It's basically the same, but I've added the "break on Sqrt" suggestion and changed some of the variables around to make it fit better for me. (I was working on Euler and needed the 10001th prime)

    0 讨论(0)
提交回复
热议问题