Meest efficiënte code voor de eerste 10000 priemgetallen?

stemmen
49

Ik wil de eerste 10000 priemgetallen te drukken. Kan iemand mij de meest efficiënte code voor dit? verduidelijking:

  1. Het maakt niet uit of je code is inefficiënt voor n> 10000.
  2. De grootte van de code doet er niet toe.
  3. Je kunt niet zomaar harde code de waarden op enige wijze.
De vraag is gesteld op 03/08/2008 om 06:45
bron van user
In andere talen...                            


29 antwoorden

stemmen
41

De Zeef van Atkin is waarschijnlijk wat je zoekt, zijn bovengrens looptijd is O (N / log log N).

Als u alleen de nummers 1 meer en 1 minder dan de veelvouden van 6 lopen, zou het zelfs sneller, omdat alle priemgetallen boven de 3 zijn 1 afstand van enkele veelvoud van zes. Bron voor mijn verklaring

antwoordde op 03/08/2008 om 07:03
bron van user

stemmen
4

Niet efficiënt helemaal niet, maar u kunt een reguliere expressie gebruiken om te testen voor de priemgetallen.

/^1?$|^(11+?)\1+$/

Deze test of gedurende een tekenreeks die bestaat uit k1” s, k is niet prime (dat wil zeggen of de reeks bestaat uit een “ 1” of een aantal “ 1” s die worden uitgedrukt als n -ary product).

antwoordde op 03/08/2008 om 19:52
bron van user

stemmen
4

Ik heb code gevonden op de aangepaste CodeProject om de volgende te maken:

ArrayList primeNumbers = new ArrayList();

for(int i = 2; primeNumbers.Count < 10000; i++) {
    bool divisible = false;

    foreach(int number in primeNumbers) {
        if(i % number == 0) {
            divisible = true;
        }
    }

    if(divisible == false) {
        primeNumbers.Add(i);
        Console.Write(i + " ");
    }
}

Het testen van dit op mijn ASP.NET Server nam de rountine ongeveer 1 minuut te lopen.

antwoordde op 05/08/2008 om 20:55
bron van user

stemmen
35

Ik adviseer een zeef, ofwel de Zeef van Eratosthenes of de Zeef van Atkin.

De zeef of Eratosthenes is waarschijnlijk de meest intuïtieve methode voor het vinden van een lijst van priemgetallen. In principe heb je:

  1. Noteer een lijst van nummers 2 tot welke limiet die u wilt, laten we zeggen 1000.
  2. Neem het eerste nummer dat niet is afgedaan (voor de eerste iteratie is dit 2) en steek korting op alle veelvouden van dat nummer uit de lijst.
  3. Herhaal stap 2 tot u het einde van de lijst te bereiken. Alle nummers die niet worden afgedaan zijn prime.

Uiteraard zijn er een flink aantal optimalisaties die gedaan kan worden om dit algoritme sneller te laten werken, maar dit is het basisidee.

De zeef van Atkin maakt gebruik van een soortgelijke aanpak, maar helaas heb ik er niet genoeg over om het uit te leggen weten. Maar ik weet wel dat het algoritme ik gekoppeld duurt 8 seconden om erachter te komen alle priemgetallen tot 1000000000 op een oude Pentium II-350

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

Zeef van Atkin Source Code: http://cr.yp.to/primegen.html

antwoordde op 06/08/2008 om 00:49
bron van user

stemmen
3

Zeef van Eratosthenes is de weg te gaan, vanwege de eenvoud en snelheid. Mijn implementatie in C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

int main(void)
{
    unsigned int lim, i, j;

    printf("Find primes upto: ");
    scanf("%d", &lim);
    lim += 1;
    bool *primes = calloc(lim, sizeof(bool));

    unsigned int sqrtlim = sqrt(lim);
    for (i = 2; i <= sqrtlim; i++)
        if (!primes[i])
            for (j = i * i; j < lim; j += i)
                primes[j] = true;

    printf("\nListing prime numbers between 2 and %d:\n\n", lim - 1);
    for (i = 2; i < lim; i++)
        if (!primes[i])
            printf("%d\n", i);

    return 0;
}

CPU Tijd om priemgetallen te vinden (op de Pentium Dual Core E2140 1,6 GHz, met behulp van single core)

~ 4s lim = 100.000.000

antwoordde op 21/08/2008 om 00:45
bron van user

stemmen
11

GateKiller , wat dacht je van het toevoegen van een breakaan die ifin de foreachloop? Dat zou versnellen dingen veel , want als je net als 6 deelbaar is door 2 je hoeft niet te controleren met 3 en 5. (ik zou uw oplossing vote up toch als ik had genoeg reputatie :-) ...)

ArrayList primeNumbers = new ArrayList();

for(int i = 2; primeNumbers.Count < 10000; i++) {
    bool divisible = false;

    foreach(int number in primeNumbers) {
        if(i % number == 0) {
            divisible = true;
            break;
        }
    }

    if(divisible == false) {
        primeNumbers.Add(i);
        Console.Write(i + " ");
    }
}
antwoordde op 27/08/2008 om 21:26
bron van user

stemmen
7

Met behulp van GMP, kan men de volgende brief:

#include <stdio.h>
#include <gmp.h>

int main() {
  mpz_t prime;
  mpz_init(prime);
  mpz_set_ui(prime, 1);
  int i;
  char* num = malloc(4000);
  for(i=0; i<10000; i++) {
    mpz_nextprime(prime, prime);
    printf("%s, ", mpz_get_str(NULL,10,prime));
  }
}

Op mijn 2,33 GHz MacBook Pro, het voert als volgt:

time ./a.out > /dev/null

real    0m0.033s
user    0m0.029s
sys    0m0.003s

Het berekenen van 1.000.000 priemgetallen op dezelfde laptop:

time ./a.out > /dev/null

real    0m14.824s
user    0m14.606s
sys     0m0.086s

GMP is sterk geoptimaliseerd voor dit soort dingen. Tenzij je echt wilt om de algoritmes te begrijpen door het schrijven van uw eigen, zou je worden geadviseerd om libgmp gebruiken onder C.

antwoordde op 29/08/2008 om 08:06
bron van user

stemmen
17

Dit is niet strikt tegen de hardcoding beperking, maar komt erg dichtbij. Waarom niet programmatisch downloaden van deze lijst en print het uit, in plaats daarvan?

http://primes.utm.edu/lists/small/10000.txt

antwoordde op 31/08/2008 om 23:20
bron van user

stemmen
9

@Matt: log (log (10000)) is ~ 2

Van het Wikipedia artikel (die u geciteerd) Zeef van Atkin :

Deze zeef berekent priemgetallen tot N O(N/log log N)bewerkingen met slechts N 02/01 + o (1) bits geheugen. Dat is een beetje beter dan de zeef van Eratosthenes die gebruik maakt van O(N) operaties en O (N 1/2 (log log N) / log N) bits geheugen (AOL Atkin, DJ Bernstein, 2004) . Deze asymptotische computationele complexiteit omvatten eenvoudige optimalisaties, zoals wielen factorisatie, en het splitsen van de berekening kleinere blokken.

Gezien asymptotische computationele complexiteit langs O(N)(voor Eratosthenes) en O(N/log(log(N)))(voor Atkin) kunnen we niet zeggen (voor kleine N=10_000), die algoritme, indien uitgevoerd zullen worden versneld.

Achim Flammenkamp schreef in de zeef van Eratosthenes :

geciteerd door:

@ num1

Voor grotere intervallen ongeveer 10 ^ 9, zeker voor die> 10 ^ 10, wordt de Zeef van Eratosthenes overtroffen door de zeef van Atkins en Bernstein die reduceerbare binaire kwadratische vorm gebruikt. Zie hun papier voor achtergrond informatie, alsmede paragraaf 5 van Ph.D. W. Galway scriptie.

Daarom is voor de 10_000Zeef van Eratosthenes sneller dan Zeef van Atkin zijn.

Om OP antwoord op de code wordt prime_sieve.c (geciteerd door num1)

antwoordde op 06/10/2008 om 21:03
bron van user

stemmen
2

Aanpassing en naar aanleiding van GateKiller , hier is de definitieve versie die ik heb gebruikt.

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

Het is in principe hetzelfde, maar ik heb de "break op Wortel" suggestie toegevoegd en gewijzigd enkele van de variabelen rond het geschikt te maken beter voor mij. (Ik was bezig met Euler en moest het 10001th prime)

antwoordde op 16/02/2009 om 06:17
bron van user

stemmen
2

De Zeef lijkt het verkeerde antwoord. De zeef geeft u de priemgetallen tot een aantal N , niet de eerste N priemgetallen. Run @Imran of @Andrew Szeto, en krijg je de priemgetallen tot en met N.

De zeef misschien nog bruikbaar zijn als je blijven proberen zeven voor de steeds grotere aantallen totdat u een bepaalde grootte van uw resultaat set hit, en het gebruik van sommige caching van nummers reeds verkregen, maar ik denk dat het zou nog steeds niet sneller dan een oplossing, zoals @ Pat's .

antwoordde op 19/06/2009 om 19:12
bron van user

stemmen
3

Hier is een zeef van Eratosthenes die ik schreef in PowerShell een paar dagen geleden. Het heeft een parameter voor het identificeren van het aantal priemgetallen dat moet worden geretourneerd.

#
# generate a list of primes up to a specific target using a sieve of eratosthenes
#
function getPrimes { #sieve of eratosthenes, http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
    param ($target,$count = 0)
    $sieveBound = [math]::ceiling(( $target - 1 ) / 2) #not storing evens so count is lower than $target
    $sieve = @($false) * $sieveBound
    $crossLimit = [math]::ceiling(( [math]::sqrt($target) - 1 ) / 2)
    for ($i = 1; $i -le $crossLimit; $i ++) {
        if ($sieve[$i] -eq $false) {
            $prime = 2 * $i + 1
            write-debug "Found: $prime"
            for ($x = 2 * $i * ( $i + 1 ); $x -lt $sieveBound; $x += 2 * $i + 1) {
                $sieve[$x] = $true
            }
        }
    }
    $primes = @(2)
    for ($i = 1; $i -le $sieveBound; $i ++) {
        if($count -gt 0 -and $primes.length -ge $count) {
            break;
        }
        if($sieve[$i] -eq $false) {
            $prime = 2 * $i + 1
            write-debug "Output: $prime"
            $primes += $prime
        }
    }
    return $primes
}
antwoordde op 07/09/2009 om 19:52
bron van user

stemmen
2

in Python

import gmpy
p=1
for i in range(10000):
    p=gmpy.next_prime(p)
    print p 
antwoordde op 22/02/2010 om 08:45
bron van user

stemmen
0

Ik heb dit met behulp van python geschreven, zoals ik net begonnen met het leren, en het werkt prima. De 10.000ste prime te genereren door deze code op als dezelfde als vermeld in http://primes.utm.edu/lists/small/10000.txt . Om te controleren of neen priemgetal is of niet, delen nmet de cijfers uit 2naar sqrt(n). Als een van deze reeks van nummer perfect verdeelt ndan is het niet prime.

import math
print ("You want prime till which number??")
a = input()
a = int(a)
x = 0
x = int(x)
count = 1
print("2 is prime number")
for c in range(3,a+1):
    b = math.sqrt(c)
    b = int(b)
    x = 0
    for b in range(2,b+1):
        e  = c % b
        e = int(e)
        if (e == 0):
            x = x+1
    if (x == 0):
        print("%d is prime number" % c)
        count = count + 1
print("Total number of prime till %d is %d" % (a,count))
antwoordde op 27/12/2010 om 18:37
bron van user

stemmen
1

Hier is mijn VB 2008 code, die alle priemgetallen <10.000.000 vondsten in 1 min 27 secs op mijn werk laptop. Het slaat zelfs nummers en alleen zoekt naar priemgetallen die <de wortel van de test nummer. Het is alleen bedoeld om priemgetallen van 0 te vinden om een ​​sentinal waarde.

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
antwoordde op 11/03/2011 om 03:25
bron van user

stemmen
0

Ik geef wat tijd aan het schrijven van een programma voor het berekenen van een veel priemgetallen en dit is de code die ik ben gewend aan een tekstbestand met de eerste 1.000.000.000 priemgetallen te berekenen. Het is in het Duits, maar het interessante deel is de methode calcPrimes(). De priemgetallen worden opgeslagen in een array genaamd Primzahlen. Ik beveel een 64-bit CPU, omdat de berekeningen zijn met 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);
        }
    }
}
antwoordde op 23/04/2012 om 20:46
bron van user

stemmen
9

In Haskell, kunnen we naar beneden voor woord te schrijven bijna woord de wiskundige definitie van de zeef van Eratosthenes, " priemgetallen zijn natuurlijke getallen boven de 1 zonder enige samengestelde nummers, waarbij composieten worden gevonden door opsomming van multiples elk prime's ":

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

primes !! 10000 is vrijwel direct.

Referenties:


De bovenstaande code wordt gemakkelijk aangepast worden in het werken op slechts odds primes = 2:3:minus [5,7..] (foldr (\p r -> p*p : union [p*p+2*p, p*p+4*p..] r) [] (tail primes)). Tijd complexiteit is veel verbeterd (tot zowat een log factor boven optimaal) door het vouwen in een boom-achtige structuur, en ruimte complexiteit wordt drastisch verbeterd door meertraps priemgetallen productie , 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 de haakjes worden gebruikt voor het groeperen, is een functie oproep aangeduid door gewoon naast elkaar, (:)is een cons operator voor lijsten, en (.)is een functioneel samenstelling operator: (f . g) x = (\y-> f (g y)) x = f (g x)).

antwoordde op 24/04/2012 om 17:30
bron van user

stemmen
-1
using System;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            int n, i = 3, j, c;
            Console.WriteLine("Please enter your integer: ");
            n = Convert.ToInt32(Console.ReadLine());
            if (n >= 1)
            {
                Console.WriteLine("First " + n + " Prime Numbers are");
                Console.WriteLine("2");
            }
            for(j=2;j<=n;)
            {
                for(c=2;c<=i-1;c++)
                {
                    if(i%c==0)
                        break;
                }
                    if(c==i)
                    {
                        Console.WriteLine(i);
                        j++;
                    }
                    i++;                                
            }
            Console.Read();
        }
    }
}
antwoordde op 08/05/2012 om 05:15
bron van user

stemmen
1

De volgende Mathcad code berekende de eerste miljoen priemgetallen in minder dan 3 minuten.

Houd in gedachten dat dit zal worden met behulp van floating point verdubbelt voor alle nummers en is in principe geïnterpreteerd. Ik hoop dat de syntax is duidelijk.

voer image beschrijving hier

antwoordde op 02/03/2014 om 02:15
bron van user

stemmen
1

Hier is een C ++ oplossing via een vorm van SoE:

#include <iostream>
#include <deque>

typedef std::deque<int> mydeque;

void my_insert( mydeque & factors, int factor ) {
    int where = factor, count = factors.size();
    while( where < count && factors[where] ) where += factor;
    if( where >= count ) factors.resize( where + 1 );
    factors[ where ] = factor;
}

int main() {
    mydeque primes;
    mydeque factors;
    int a_prime = 3, a_square_prime = 9, maybe_prime = 3;
    int cnt = 2;
    factors.resize(3);
    std::cout << "2 3 ";

    while( cnt < 10000 ) {
        int factor = factors.front();
        maybe_prime += 2;
        if( factor ) {
            my_insert( factors, factor );
        } else if( maybe_prime < a_square_prime ) {
            std::cout << maybe_prime << " ";
            primes.push_back( maybe_prime );
            ++cnt;
        } else {
            my_insert( factors, a_prime );
            a_prime = primes.front();
            primes.pop_front();
            a_square_prime = a_prime * a_prime;
        }
        factors.pop_front();
    }

    std::cout << std::endl;
    return 0;
}

Merk op dat deze versie van de Sieve priemgetallen voor onbepaalde tijd kan berekenen.

Merk ook op, de STL dequeneemt O(1)de tijd om uit te voeren push_back, pop_fronten random access al subscripting.

De resizeoperatie duurt O(n)tijd, waarbij nhet aantal elementen worden toegevoegd. Als gevolg van de manier waarop we deze functie gebruikt, kunnen we de behandeling van deze is een klein constant.

Het lichaam van de whilelus my_insertwordt uitgevoerd O(log log n)tijden, waarbij ngelijk is aan de variabele maybe_prime. Dit komt omdat de conditie expressie van het whilezal evalueren om waar één keer voor elk belangrijkste factor maybe_prime. Zie " Divisor functie " op Wikipedia.

Te vermenigvuldigen met het aantal keren my_insertwordt genoemd, laat zien dat het moet nemen O(n log log n)de tijd om een lijst van npriemgetallen ... en dat is, niet verrassend, de tijd dat de uitvoering, waardoor de zeef van Eratosthenes wordt verondersteld te hebben.

Hoewel deze code is efficiënt, het is niet de meest efficiënte ... Ik zou raden het gebruik van een gespecialiseerde bibliotheek voor priemgetallen generatie, zoals primesieve . Elke echt efficiënte, goed geoptimaliseerd oplossing, zullen meer code duren dan iemand wil typen in StackOverflow.

antwoordde op 16/04/2016 om 18:33
bron van user

stemmen
2

De door BenGoldberg genoemde deque zeef algoritme verdient nadere beschouwing niet alleen omdat het zeer elegant, maar ook omdat het af en toe nuttig kan zijn in de praktijk (in tegenstelling tot de zeef van Atkin, dat een zuiver academische oefening).

Het basisidee achter de deque zeef algoritme is een kleine, glijdende zeef die slechts groot genoeg is om ten minste een afzonderlijke meervoudige bevatten voor elk van de momenteel 'actieve' priemfactoren gebruiken - dwz priemgetallen waarvan het kwadraat niet overschrijdt laagste nummer momenteel vertegenwoordigd door de bewegende zeef. Een ander verschil met de SoE dat de deque zeef slaat de feitelijke elementen in de sleuven van composieten, niet booleans.

Het algoritme breidt de grootte van de zeef zo ​​vaak als nodig, wat resulteert in vrij gelijkmatige prestaties over een breed scala totdat de zeef begint aanzienlijk groter dan de capaciteit van de CPU L1 cache. De laatste prime die volledig past is 25.237.523 (het 1,579,791st prime), dat een ruwe schatting geven voor een redelijke actieradius van het algoritme geeft.

Het algoritme is vrij eenvoudig en robuust, en het heeft zelfs de prestaties over een veel breder bereik dan een unsegmented Zeef van Eratosthenes. Dit laatste is een stuk sneller, zolang de zeef past volledig in de cache, dat wil zeggen tot 2 ^ 16 voor een odds-only zeef met byte-sized bools. Dan daalt de prestaties meer en meer, maar het blijft altijd aanzienlijk sneller dan de Deque ondanks de handicap (althans in gecompileerde talen zoals C / C ++, Pascal of Java / C #).

Hier is een weergave van de Deque zeef algoritme in C #, omdat ik die taal te vinden - ondanks de vele gebreken - veel praktischer voor prototyping algoritmen en experimenteren dan de uiterst omslachtige en pedant C ++. (Kanttekening: Ik gebruik de gratis LINQPad die het mogelijk maakt naar rechts in duiken, zonder al het geknoei met het opzetten van projecten, makefiles, directories of wat, en het geeft me dezelfde mate van interactiviteit als een python prompt).

C # heeft geen expliciete deque type, maar de vlakte List<int>werkt goed genoeg voor het aantonen van het algoritme.

Let op: deze versie niet een deque gebruiken voor de priemgetallen, omdat het gewoon geen zin om af te knallen sqrt (n) van n priemgetallen. Wat zou het zijn om 100 priemgetallen te verwijderen en te vertrekken 9900? Tenminste deze manier alle priemgetallen worden verzameld in een nette vector, klaar voor verdere verwerking.

static List<int> deque_sieve (int n = 10000)
{
    Trace.Assert(n >= 3);

    var primes = new List<int>()  {  2, 3  };
    var sieve = new List<int>()  {  0, 0, 0  };

    for (int sieve_base = 5, current_prime_index = 1, current_prime_squared = 9; ; )
    {
        int base_factor = sieve[0];

        if (base_factor != 0)
        {
            // the sieve base has a non-trivial factor - put that factor back into circulation
            mark_next_unmarked_multiple(sieve, base_factor);
        }
        else if (sieve_base < current_prime_squared)  // no non-trivial factor -> found a non-composite
        {
            primes.Add(sieve_base);

            if (primes.Count == n)
                return primes;
        }
        else // sieve_base == current_prime_squared
        {
            // bring the current prime into circulation by injecting it into the sieve ...
            mark_next_unmarked_multiple(sieve, primes[current_prime_index]);

            // ... and elect a new current prime
            current_prime_squared = square(primes[++current_prime_index]);
        }

        // slide the sieve one step forward
        sieve.RemoveAt(0);  sieve_base += 2;
    }
}

Hier zijn de twee helper functies:

static void mark_next_unmarked_multiple (List<int> sieve, int prime)
{
    int i = prime, e = sieve.Count;

    while (i < e && sieve[i] != 0)
        i += prime;

    for ( ; e <= i; ++e)  // no List<>.Resize()...
        sieve.Add(0);

    sieve[i] = prime;
}

static int square (int n)
{
    return n * n;
}

Waarschijnlijk is de makkelijkste manier om te begrijpen het algoritme is voor te stellen als een speciale gesegmenteerde Zeef van Eratosthenes met een segment van 1, vergezeld van een overloop gebied waar de priemgetallen tot rust komen wanneer ze schieten over het einde van het segment. Behalve dat de enkele cel van het segment (aka sieve[0]) is al gezeefd als we bij het, omdat het overreden terwijl het was onderdeel van de overloop gebied.

Het getal dat wordt weergegeven door sieve[0]wordt vastgehouden sieve_base, ofschoon sieve_frontof window_basezou ook een goede namen waarmee parallellen Ben's code of implementaties van gesegmenteerde / gevensterde zeven trekken.

Wanneer sieve[0]een niet-nul waarde bevat dan die waarde is een factor sieve_base, die dus als samengesteld te herkennen. Omdat cel 0 is een veelvoud van die factor is het gemakkelijk om de volgende hop, dat is gewoon 0 plus die factor te berekenen. Mocht die cel al worden bezet door een andere factor dan hebben we de factor opnieuw toe te voegen eenvoudig, en zo verder tot we een veelvoud van de factor waar geen andere factor momenteel geparkeerd (de uitbreiding van de zeef indien nodig) te vinden. Dit betekent ook dat er geen noodzaak voor het opslaan van het huidige werk verschuivingen van de verschillende priemgetallen van het ene segment naar het andere, zoals bij een gewone gesegmenteerde zeef. Wanneer we een factor in te vinden sieve[0], zijn huidige werken offset 0.

De huidige premier komt in het spel op de volgende manier. Een goed kan binnen huidige na haar optreden in de stroom wordt (dwz nadat is gedetecteerd als een eerste, omdat niet gemarkeerd met een factor), en zal stroom blijven tot het exacte moment waarop sieve[0]het vakje komt. Alle lagere veelvouden van deze prime moet zijn geschrapt als gevolg van de activiteiten van kleinere priemgetallen, net als in een normale SoE. Maar geen van de kleinere priemgetallen kan toeslaan bij het plein, omdat de enige factor van het plein is de belangrijkste zelf en het is nog niet in omloop is op dit punt. Dat verklaart de door het algoritme in de zaak acties sieve_base == current_prime_squared(hetgeen inhoudt sieve[0] == 0, door de manier).

Nu het geval sieve[0] == 0 && sieve_base < current_prime_squaredis eenvoudig te verklaren: het betekent dat sieve_basegeen veelvoud van elke van de priemgetallen kleiner dan de huidige prime, of anders zou zijn gemarkeerd als composiet. Ik kan niet een hogere veelvoud van de huidige prime ofwel, omdat de waarde van minder dan plein van de huidige premier is. Daarom moet het een nieuwe premier te zijn.

Het algoritme is duidelijk geïnspireerd door de zeef van Eratosthenes, maar ook het is natuurlijk heel anders. De Zeef van Eratosthenes ontleent zijn superieure snelheid van de eenvoud van de elementaire bewerkingen: één index toevoeging en een opslag voor elke stap van de bewerking is alles wat het doet voor uitgestrekte tijd.

Hier is een eenvoudige, unsegmented Zeef van Eratosthenes die ik normaal gebruikt voor zeven factor priemgetallen in het ushort traject, dat wil zeggen tot 2 ^ 16. Voor deze post heb ik het aangepast om te werken meer dan 2 ^ 16 door vervanging intvoorushort

static List<int> small_odd_primes_up_to (int n)
{
    var result = new List<int>();

    if (n < 3)
        return result;

    int sqrt_n_halved = (int)(Math.Sqrt(n) - 1) >> 1, max_bit = (n - 1) >> 1;
    var odd_composite = new bool[max_bit + 1];

    for (int i = 3 >> 1; i <= sqrt_n_halved; ++i)
        if (!odd_composite[i])
            for (int p = (i << 1) + 1, j = p * p >> 1; j <= max_bit; j += p)
                odd_composite[j] = true;

    result.Add(3);  // needs to be handled separately because of the mod 3 wheel

    // read out the sieved primes
    for (int i = 5 >> 1, d = 1; i <= max_bit; i += d, d ^= 3)
        if (!odd_composite[i])
            result.Add((i << 1) + 1);

    return result;
}

Wanneer de eerste zeven 10000 priemgetallen typische L1 cache 32 KiByte wordt overschreden, maar de functie is nog steeds erg snel (fractie van een milliseconde, zelfs in C #).

Als u deze code te vergelijken met de Deque zeef dan is het makkelijk om te zien dat de activiteiten van de Deque zeef zijn een stuk ingewikkelder, en het kan niet effectief afschrijving van de overhead, omdat het doet altijd de kortst mogelijke traject van kruisingen-off in een rij (precies één crossing-off, na het overslaan van alle veelvouden die al zijn afgedaan).

Let op: de C # code gebruikt intin plaats van uint, omdat nieuwere compilers hebben een gewoonte van het genereren van substandard-code voor uint, waarschijnlijk om mensen te duwen in de richting van integers ... In de C ++ versie van de bovenstaande code gebruikte ik unsignedhet hele, natuurlijk; de benchmark moest in C ++, omdat ik wilde dat het op basis van een zogenaamd adequate soort deque ( std::deque<unsigned>; er was geen prestatiewinst van het gebruik unsigned short). Hier zijn de nummers voor mijn Haswell laptop (VC ++ 2015 / x64):

deque vs simple: 1.802 ms vs 0.182 ms
deque vs simple: 1.836 ms vs 0.170 ms 
deque vs simple: 1.729 ms vs 0.173 ms

Let op: de C # keer zijn vrij veel precies het dubbele van de C ++ timings, dat is vrij goed voor C # en het laat zien dat List<int>is niet traag, zelfs als misbruikt als deque.

De eenvoudige zeef code blaast steeds de deque uit het water, terwijl zij reeds aanwezig is dan het normale werkbereik (L1 cache is overschreden met 50%, met bijbehorende cache thrashende). De dominerende rol hier is het uitlezen van de gezeefde priemgetallen, en dit is niet veel door de cache probleem beïnvloed. In elk geval is het aanstellen van zeven factoren factoren, namelijk het niveau 0 in een 3-niveau zeef hiërarchie, en kenmerkend het moet slechts een paar honderd factoren of een klein aantal duizenden keren. Vandaar zijn eenvoud.

Prestatie kan worden verbeterd met meer dan een orde van grootte onder toepassing van een gesegmenteerde zeef en optimaliseren van de code voor het extraheren van het gezeefde primes (getrapt mod 3 en afgerold twee of mod 15 en eenmaal afgerold), en met nog meer onder druk zouden kunnen worden geperst uit de code met behulp van een mod 16 of 30 mod wheel heeft alle eigenschappen (dat wil zeggen volledig afrollen van alle resten). Zoiets wordt uitgelegd in mijn antwoord op prime gepositioneerd priemgetal Zoek dan op Code Review, waarin een soortgelijk probleem werd besproken. Maar het is moeilijk om het punt in het verbeteren van minder dan een milliseconde tijden voor een eenmalige taak te zien ...

Om alles een beetje in perspectief te plaatsen, hier zijn de C ++ timing voor zeven tot 100.000.000:

deque vs simple: 1895.521 ms vs 432.763 ms
deque vs simple: 1847.594 ms vs 429.766 ms
deque vs simple: 1859.462 ms vs 430.625 ms

In tegenstelling, een gesegmenteerde zeef in C # met een paar toeters en bellen doet hetzelfde werk in 95 ms (geen C ++ timings beschikbaar, aangezien ik doe code daagt alleen in C # op het moment).

Zaken kan beslist anders uitzien in een geïnterpreteerde taal als Python waar elke transactie een hoge kosten en de interpreter overhead verkleint alle verschillen als gevolg van voorspelde vs. mispredicted takken of sub-cycle ops (verschuiving, toevoeging) vs. multicyclische ops (vermenigvuldigen , en misschien zelfs divisie). Die is gebonden aan de eenvoud voordeel van de Zeef van Eratosthenes eroderen, en dit zou de deque oplossing een beetje aantrekkelijker te maken.

Ook veel van de tijden door andere respondenten in dit onderwerp waarschijnlijk gedomineerd door uitgang tijd . Dat is een heel andere oorlog, waar mijn belangrijkste wapen is een eenvoudige klasse als volgt uit:

class CCWriter
{
    const int SPACE_RESERVE = 11;  // UInt31 + '\n'

    public static System.IO.Stream BaseStream;
    static byte[] m_buffer = new byte[1 << 16];  // need 55k..60k for a maximum-size range
    static int m_write_pos = 0;
    public static long BytesWritten = 0;         // for statistics

    internal static ushort[] m_double_digit_lookup = create_double_digit_lookup();

    internal static ushort[] create_double_digit_lookup ()
    {
        var lookup = new ushort[100];

        for (int lo = 0; lo < 10; ++lo)
            for (int hi = 0; hi < 10; ++hi)
                lookup[hi * 10 + lo] = (ushort)(0x3030 + (hi << 8) + lo);

        return lookup;
    }

    public static void Flush ()
    {
        if (BaseStream != null && m_write_pos > 0)
            BaseStream.Write(m_buffer, 0, m_write_pos);

        BytesWritten += m_write_pos;
        m_write_pos = 0;
    }

    public static void WriteLine ()
    {
        if (m_buffer.Length - m_write_pos < 1)
            Flush();

        m_buffer[m_write_pos++] = (byte)'\n';
    }

    public static void WriteLinesSorted (int[] values, int count)
    {
        int digits = 1, max_value = 9;

        for (int i = 0; i < count; ++i)
        {
            int x = values[i];

            if (m_buffer.Length - m_write_pos < SPACE_RESERVE)
                Flush();

            while (x > max_value)
                if (++digits < 10)
                    max_value = max_value * 10 + 9;
                else
                    max_value = int.MaxValue;               

            int n = x, p = m_write_pos + digits, e = p + 1;

            m_buffer[p] = (byte)'\n';

            while (n >= 10)
            {
                int q = n / 100, w = m_double_digit_lookup[n - q * 100];
                n = q;
                m_buffer[--p] = (byte)w;
                m_buffer[--p] = (byte)(w >> 8);
            }

            if (n != 0 || x == 0)
                m_buffer[--p] = (byte)((byte)'0' + n);

            m_write_pos = e;
        }
    }
}

Dat kost minder dan 1 ms voor het schrijven van 10000 (gesorteerd) nummers. Het is een statische klasse, omdat het bedoeld is voor tekstuele opname in het coderen uitdaging inzendingen, met een minimum aan gedoe en zero overhead.

In het algemeen vond ik dat het is veel sneller als gericht gewerkt wordt aan hele batches, wat betekent zeef een bepaald bereik, pak dan alle priemgetallen in een vector / array, dan schiet de hele reeks, dan zeef de volgende range en ga zo maar door, in plaats van samen te mengen alles. Met afzonderlijke functies gericht op specifieke taken maakt het ook makkelijker te mixen en matchen, het stelt hergebruik, en het vergemakkelijkt de ontwikkeling / testen.

antwoordde op 19/04/2016 om 17:07
bron van user

stemmen
1

Met behulp van Zeef van Eratosthenes, wordt berekening vrij sneller te vergelijken met "bekende brede" priemgetallen algoritme.

Door het gebruik van pseudo-code van het wiki ( https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes ), ik in staat zijn om de oplossing op C # hebben.

/// 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) neemt 2s en 330ms.

LET OP : waarde kan variëren afhankelijk van de hardware specificaties.

antwoordde op 12/05/2016 om 03:40
bron van user

stemmen
0

Ik heb gewerkt aan vondst priemgetallen voor ongeveer een jaar. Dit is wat ik gevonden om de snelste te zijn:

import static java.lang.Math.sqrt;
import java.io.PrintWriter;
import java.io.File;
public class finder {
    public static void main(String[] args) {
        primelist primes = new primelist();
        primes.insert(3);
        primes.insert(5);
        File file = new File("C:/Users/Richard/Desktop/directory/file0024.txt");
        file.getParentFile().mkdirs();
        long time = System.nanoTime();
        try{
            PrintWriter printWriter = new PrintWriter ("file0024.txt"); 
            int linenum = 0;
            printWriter.print("2");
            printWriter.print (" , ");
            printWriter.print("3");
            printWriter.print (" , ");
            int up;
            int down;           
            for(int i =1; i<357913941;i++){//
                if(linenum%10000==0){
                    printWriter.println ("");
                    linenum++;
                }
                down = i*6-1;
                if(primes.check(down)){
                    primes.insert(down);
                    //System.out.println(i*6-1);
                    printWriter.print ( down );
                    printWriter.print (" , ");
                    linenum++;  
                }
                up = i*6+1;
                if(primes.check(up)){
                    primes.insert(up);
                    //System.out.println(i*6+1);
                    printWriter.print ( up );
                    printWriter.print (" , ");
                    linenum++;  
                }
            }
            printWriter.println ("Time to execute");
            printWriter.println (System.nanoTime()-time);
            //System.out.println(primes.length);
            printWriter.close ();
        }catch(Exception e){}
    } 
}
class node{
    node next;
    int x;
    public node (){
        node next;
        x = 3;
    }
    public node(int z) {
        node next;
        x = z;
    }
}
class primelist{
    node first;
    int length =0;
    node current;
    public void insert(int x){
        node y = new node(x);
        if(current == null){
            current = y;
            first = y;
        }else{
            current.next = y;
            current = y;
        }
        length++;
    }
    public boolean check(int x){
        int p = (int)sqrt(x);
        node y = first;
        for(int i = 0;i<length;i++){
            if(y.x>p){
                return true;
            }else if(x%y.x ==0){
                return false;
            }
            y = y.next;
        }
        return true;
    }
}

1902465190909 nano seconden om 2147483629 te krijgen vanaf 2.

antwoordde op 14/08/2016 om 00:20
bron van user

stemmen
0

Hier is mijn code die eerste 10.000 priemgetallen vindt in 0,049655 seconde op mijn laptop, 1.000.000 eerste priemgetallen in minder dan 6 seconden en de eerste 2.000.000 in 15 seconden
enige toelichting. Deze methode maakt gebruik van 2 technieken om priemgetal vinden

  1. allereerst een niet-priemgetal is een samenstelling van veelvouden van priemgetallen zodat deze code test door het testnummer delen door kleinere priemgetallen in plaats van elke getal verlaagt deze berekening door minstens 10 maal voor een 4-cijferig nummer en nog voor een groter aantal
  2. tweede naast delen door eerste, alleen deelt door priemgetallen die kleiner of gelijk is aan de wortel van het aantal geteste verdere berekeningen sterk verminderen zijn, dit werkt omdat elk getal dat groter is dan wortel van het aantal tegenhanger nummer hebben dat moet kleiner zijn dan de wortel van het aantal zijn, maar omdat we alle getallen kleiner dan de wortel al hebben getest, dus hoeven we niet bezig te houden met getal groter dan de wortel van het aantal wordt getest.

Sample-uitgang voor de eerste 10.000 priemgetal
https://drive.google.com/open?id=0B2QYXBiLI-lZMUpCNFhZeUphck0 https://drive.google.com/open?id=0B2QYXBiLI-lZbmRtTkZETnp6Ykk

Hier is de code in C taal, Enter 1 en vervolgens 10.000 tot afdruk van de eerste 10.000 priemgetallen.
Edit: Ik vergat deze bevat math bibliotheek, als je op ramen of Visual Studio is dan dat moet wel goed, maar op linux moet u de code compileren met -lm argument of de code kan niet werken
Voorbeeld: gcc -Wall -o "% e " "% f" -lm

#include <stdio.h>
#include <math.h>
#include <time.h>
#include <limits.h>

/* Finding prime numbers */
int main()
{   
    //pre-phase
    char d,w;
    int l,o;
    printf("  1. Find first n number of prime numbers or Find all prime numbers smaller than n ?\n"); // this question helps in setting the limits on m or n value i.e l or o 
    printf("     Enter 1 or 2 to get anwser of first or second question\n");
    // decision making
    do
    {
        printf("  -->");
        scanf("%c",&d);
        while ((w=getchar()) != '\n' && w != EOF);
        if ( d == '1')
        {
            printf("\n  2. Enter the target no. of primes you will like to find from 3 to 2,000,000 range\n  -->");
            scanf("%10d",&l);
            o=INT_MAX;
            printf("  Here we go!\n\n");
            break;
        }
        else if ( d == '2' )
        {
            printf("\n  2.Enter the limit under which to find prime numbers from 5 to 2,000,000 range\n  -->");
            scanf("%10d",&o);
            l=o/log(o)*1.25;
            printf("  Here we go!\n\n");
            break;
        }
        else printf("\n  Try again\n");
    }while ( d != '1' || d != '2' );

    clock_t start, end;
    double cpu_time_used;
    start = clock(); /* starting the clock for time keeping */

    // main program starts here
    int i,j,c,m,n; /* i ,j , c and m are all prime array 'p' variables and n is the number that is being tested */
    int s,x;

    int p[ l ]; /* p is the array for storing prime numbers and l sets the array size, l was initialized in pre-phase */
    p[1]=2;
    p[2]=3;
    p[3]=5;
    printf("%10dst:%10d\n%10dnd:%10d\n%10drd:%10d\n",1,p[1],2,p[2],3,p[3]); // first three prime are set
    for ( i=4;i<=l;++i ) /* this loop sets all the prime numbers greater than 5 in the p array to 0 */
        p[i]=0;

    n=6; /* prime number testing begins with number 6 but this can lowered if you wish but you must remember to update other variables too */
    s=sqrt(n); /* 's' does two things it stores the root value so that program does not have to calaculate it again and again and also it stores it in integer form instead of float*/
    x=2; /* 'x' is the biggest prime number that is smaller or equal to root of the number 'n' being tested */

    /* j ,x and c are related in this way, p[j] <= prime number x <= p[c] */

    // the main loop begins here
    for ( m=4,j=1,c=2; m<=l && n <= o;)
    /* this condition checks if all the first 'l' numbers of primes are found or n does not exceed the set limit o */
    {
            // this will divide n by prime number in p[j] and tries to rule out non-primes
            if ( n%p[j]==0 )
            {
                /* these steps execute if the number n is found to be non-prime */

                ++n; /* this increases n by 1 and therefore sets the next number 'n' to be tested */
                s=sqrt(n); /* this calaulates and stores in 's' the new root of number 'n' */
                if ( p[c] <= s && p[c] != x ) /* 'The Magic Setting' tests the next prime number candidate p[c] and if passed it updates the prime number x */
                {
                    x=p[c];
                    ++c;
                }
                j=1;
                /* these steps sets the next number n to be tested and finds the next prime number x if possible for the new number 'n' and also resets j to 1 for the new cycle */
                continue; /* and this restarts the loop for the new cycle */
            }
            // confirmation test for the prime number candidate n
            else if ( n%p[j]!=0 && p[j]==x )
            {
                /* these steps execute if the number is found to be prime */
                p[m]=n;
                printf("%10dth:%10d\n",m,p[m]);
                ++n;
                s = sqrt(n);
                ++m;
                j=1;
                /* these steps stores and prints the new prime number and moves the 'm' counter up and also sets the next number n to be tested and also resets j to 1 for the new cycle */
                continue; /* and this restarts the loop */
                /* the next number which will be a even and non-prime will trigger the magic setting in the next cycle and therfore we do not have to add another magic setting here*/
            }
            ++j; /* increases p[j] to next prime number in the array for the next cycle testing of the number 'n' */
            // if the cycle reaches this point that means the number 'n' was neither divisible by p[j] nor was it a prime number
            // and therfore it will test the same number 'n' again in the next cycle with a bigger prime number
    }
    // the loops ends
    printf("  All done !!\n");
    end = clock();
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
    printf("  Time taken : %lf sec\n",cpu_time_used);
}
antwoordde op 06/05/2017 om 11:48
bron van user

stemmen
0

Hier is de code die ik heb gemaakt:


enter code here
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT*/   

unsigned long int n;

int prime(unsigned long int);

scanf("%ld",&n);

unsigned long int val;

for(unsigned long int i=0;i<n;i++)
{
    int flag=0;

    scanf("%ld",&val);

    flag=prime(val);

    if(flag==1)
        printf("yes\n");

    else
        printf("no\n");
}

return 0;

}

int prime(unsigned long int n)
{

if(n==2) return 1;

else if (n == 1||n%2==0)  return 0;

for (unsigned long int i=3; i<=sqrt(n); i+=2)
    if (n%i == 0)
        return 0;

return 1;
}
antwoordde op 20/01/2018 om 15:50
bron van user

stemmen
0

Met behulp van de methode Array.prototype.find () in Javascript. 2214.486 ms

function isPrime (number) {

  function prime(element) {
    let start = 2;
    while (start <= Math.sqrt(element)) {
      if (element % start++ < 1) {
        return false;
      }
    }
    return element > 1;
  }

  return [number].find(prime)

}

function logPrimes (n) {

  let count = 0
  let nth = n

  let i = 0
  while (count < nth) {
    if (isPrime(i)) {
      count++
      console.log('i', i) //NOTE: If this line is ommited time to find 10,000th prime is 121.157ms
      if (count === nth) {
        console.log('while i', i)
        console.log('count', count)
      }
    }
    i++
  }

}

console.time(logPrimes)

logPrimes(10000)

console.timeEnd(logPrimes) // 2214.486ms
antwoordde op 09/06/2018 om 21:49
bron van user

stemmen
0

Ik kan u enkele tips, moet je om het te implementeren.

  1. Voor elk nummer, krijgt de helft van dat aantal. Bijvoorbeeld voor het controleren 21, alleen de rest te verkrijgen door deze te delen door range 2-10.
  2. Als het een oneven getal, alleen delen door oneven getal, en vice versa. Zoals 21, delen 3, 5, 7, 9 alleen.

Meest efficiënte methode die ik heb tot nu toe.

antwoordde op 29/07/2018 om 19:25
bron van user

stemmen
0

Omdat u als eerste 10000 priemgetallen alleen, in plaats van het coderen van complex algoritme Ik stel voor de volgende

boolean isPrime(int n){
//even but is prime
    if(n==2)
        return true;
//even numbers filtered already 
    if(n==0 || n==1 || n%2==0)
        return false;

// loop for checking only odd factors
// i*i <= n  (same as i<=sqrt(n), avoiding floating point calculations)
    for(int i=3 ; i*i <=n ; i+=2){
    // if any odd factor divides n then its not a prime!
        if(n%i==0)
            return false;
    }
// its prime now
    return true;
}

nu oproep is een priemgetal als je het nodig hebt

for(int i=1 ; i<=1000 ; i++){
    if(isPrime(i)){
       //do something
    }
}
antwoordde op 16/11/2018 om 05:34
bron van user

stemmen
0

Dit is een oude vraag, maar er is hier iets voor iedereen ontbreekt ...

Voor priemgetallen deze kleine, het proces divisie is niet dat traag ... er zijn slechts 25 priemgetallen onder 100. Met zo weinig priemgetallen te testen, en dergelijke kleine priemgetallen, kunnen we trekken uit een handige truc!

Als a coprime B, dan gcd ab = 1. relatief priem. Leuk woord. Betekent dat het niet delen geen priemfactoren . Zo kunnen we testen op deelbaarheid door verschillende priemgetallen met een GCD gesprek. Hoeveel? Nou, het product van de eerste 15 priemgetallen minder dan 2 ^ 64. En het product van de komende 10 is ook minder dan 2 ^ 64. Dat is alles 25 die we nodig hebben. Maar is het de moeite waard?

Laten we eens kijken:

check x = null $ filter ((==0) . (x `mod`)) $ [<primes up to 101>]
Prelude> length $ filter check [101,103..85600]
>>> 9975
(0.30 secs, 125,865,152 bytes

a = 16294579238595022365 :: Word64
b = 14290787196698157718
pre = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
primes = (pre ++) $ filter ((==1) . gcd a) $ filter ((==1) . gcd b) [99,101..85600]
main = print $ length primes

Prelude> main
>>> 10000
(0.05 secs, 36,387,520 bytes)

Een 6-voudige verbetering zijn.

( lengthIs om de lijst te dwingen te worden berekend. Standaard Haskell afgedrukt dingen 1 Unicode karakter per keer en dus eigenlijk het afdrukken van de lijst zal ofwel domineren de tijd of domineren het bedrag van de werkelijke code gebruikt).

Natuurlijk, dit wordt uitgevoerd in ghci - een repl running geïnterpreteerd code - op een oude laptop en het is niet de interpretatie van een van deze nummers als int64s of zelfs BigIntis, noch zal het zelfs als je het vragen om (nou ja, je kunt forceren , maar het is lelijk en niet echt help). Het is de interpretatie van elk nummer er als gegeneraliseerde Integer-achtige dingen die kunnen worden gespecialiseerd om een bepaald soort via het woordenboek, en het is het doorlopen van een gekoppelde lijst (die weg hier niet gefuseerd is omdat het niet is gecompileerd) 3 keer. Interessant is dat, met de hand het fuseren van de twee filters vertraagt het eigenlijk in de REPL.

Laten we het compileren:

...\Haskell\8.6\Testbed>Primes.exe +RTS -s
10000
606,280 bytes allocated in the heap
Total   time    0.000s  (  0.004s elapsed)

Met behulp van het rapport RTS omdat Windows. Sommige lijnen in orde gemaakt, omdat ze niet relevant zijn - ze waren andere GC gegevens of metingen van slechts een deel van de uitvoering, en samen optellen tot 0.004s (of minder). Het is ook niet constant vouwen, omdat Haskell eigenlijk niet veel van dat te doen. Als we constant vouwen onszelf ( main = print 10000), krijgen we enorm veel lager bezettingsgraad:

...Haskell\8.6\Testbed>Primes.exe +RTS -s
10000
47,688 bytes allocated in the heap
Total   time    0.000s  (  0.001s elapsed)

Letterlijk net genoeg om de runtime te laden, dan ontdekken dat er niets te doen, maar het afdrukken van een nummer en exit. Laten we toevoegen dat wiel ontbinding in factoren:

wheel = scanl (+) 7 $ cycle [4, 2, 4, 2, 4, 6, 2, 6]
primes = (pre ++) $ filter ((==1) . gcd a) $ filter ((==1) . gcd b) $ takeWhile (<85600) wheel

Total   time    0.000s  (  0.003s elapsed)

Bezuinigen ongeveer 1 / 3e ten opzichte van onze referentie van main = print 10000, maar er is zeker ruimte voor meer optimalisatie. Het is eigenlijk gestopt om een GC voeren daar bijvoorbeeld, terwijl met tweaking zou er geen hoop gebruik niet. Om een of andere reden, het opstellen want hier profileren eigenlijk snijdt de runtime omlaag tot 2 milliseconden:

Tue Nov 12 21:13 2019 Time and Allocation Profiling Report  (Final)

   Primes.exe +RTS -p -RTS

total time  =        0.00 secs   (2 ticks @ 1000 us, 1 processor)
total alloc =     967,120 bytes  (excludes profiling overheads)

Ik ga om te vertrekken dit zo is voor nu, ik ben er vrij zeker van willekeurige jitter begint te domineren.

antwoordde op 13/11/2019 om 05:49
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more