Prime number calculation fun

前端 未结 18 1754
深忆病人
深忆病人 2020-12-05 15:32

We\'re having a bit of fun here at work. It all started with one of the guys setting up a Hackintosh and we were wondering whether it was faster than a Windows Box of (nearl

相关标签:
18条回答
  • 2020-12-05 15:42

    My take at optimization, avoiding too cryptic tricks. I use the trick given by I-GIVE-TERRIBLE-ADVICE, which I knew and forgot... :-)

    public class Primes
    {
      // Original code
      public static void first()
      {
        int topPrime = 150003;
        int current = 2;
        int count = 0;
        int lastPrime = 2;
    
        long start = System.currentTimeMillis();
    
        while (count < topPrime) {
    
          boolean prime = true;
    
          int top = (int)Math.sqrt(current) + 1;
    
          for (int i = 2; i < top; i++) {
            if (current % i == 0) {
              prime = false;
              break;
            }
          }
    
          if (prime) {
            count++;
            lastPrime = current;
    //      System.out.print(lastPrime + " "); // Checking algo is correct...
          }
          if (current == 2) {
            current++;
          } else {
            current = current + 2;
          }
        }
    
        System.out.println("\n-- First");
        System.out.println("Last prime = " + lastPrime);
        System.out.println("Total time = " + (double)(System.currentTimeMillis() - start) / 1000);
      }
    
      // My attempt
      public static void second()
      {
        final int wantedPrimeNb = 150000;
        int count = 0;
    
        int currentNumber = 1;
        int increment = 4;
        int lastPrime = 0;
    
        long start = System.currentTimeMillis();
    
    NEXT_TESTING_NUMBER:
        while (count < wantedPrimeNb)
        {
          currentNumber += increment;
          increment = 6 - increment;
          if (currentNumber % 2 == 0) // Even number
            continue;
          if (currentNumber % 3 == 0) // Multiple of three
            continue;
    
          int top = (int) Math.sqrt(currentNumber) + 1;
          int testingNumber = 5;
          int testIncrement = 2;
          do
          {
            if (currentNumber % testingNumber == 0)
            {
              continue NEXT_TESTING_NUMBER;
            }
            testingNumber += testIncrement;
            testIncrement = 6 - testIncrement;
          } while (testingNumber < top);
          // If we got there, we have a prime
          count++;
          lastPrime = currentNumber;
    //      System.out.print(lastPrime + " "); // Checking algo is correct...
        }
    
        System.out.println("\n-- Second");
        System.out.println("Last prime = " + lastPrime);
        System.out.println("Total time = " + (double) (System.currentTimeMillis() - start) / 1000);
      }
    
      public static void main(String[] args)
      {
        first();
        second();
      }
    }
    

    Yes, I used a labeled continue, first time I try them in Java...
    I know I skip computation of the first few primes, but they are well known, no point to recompute them. :-) I can hard-code their output if needed! Beside, it doesn't give a decisive edge anyway.

    Results:

    -- First
    Last prime = 2015201
    Total time = 4.281

    -- Second
    Last prime = 2015201
    Total time = 0.953

    Not bad. Might be improved a bit, I suppose, but too much optimization can kill good code.

    0 讨论(0)
  • 2020-12-05 15:45

    Here is my take on it. The program is writtern in C and takes 50 milliseconds on my laptop(Core 2 Duo, 1 GB Ram). I am keeping all the calculated primes in an array and trying divisibility only till sqrt of number. Of course, this doesnt work when we need very large number of primes(tried with 100000000) as array grows too big and gives seg fault.

    /*Calculate the primes till TOTALPRIMES*/
    #include <stdio.h>
    #define TOTALPRIMES 15000
    
    main(){
    int primes[TOTALPRIMES];
    int count;
    int i, j, cpr;
    char isPrime;
    
    primes[0] = 2;
    count = 1;
    
    for(i = 3; count < TOTALPRIMES; i+= 2){
        isPrime = 1;
    
        //check divisiblity only with previous primes
        for(j = 0; j < count; j++){
            cpr = primes[j];
            if(i % cpr == 0){
                isPrime = 0;
                break;
            }
            if(cpr*cpr > i){
                break;
            }
        }
        if(isPrime == 1){
            //printf("Prime: %d\n", i);
            primes[count] = i;
            count++;
        }
    
    
    }
    
    printf("Last prime = %d\n", primes[TOTALPRIMES - 1]);
    }
    
    $ time ./a.out 
    Last prime = 163841
    real    0m0.045s
    user    0m0.040s
    sys 0m0.004s
    
    0 讨论(0)
  • 2020-12-05 15:47

    Here's my solution... its fairly fast... it calculates the primes between 1 and 10,000,000 in 3 seconds on my machine (core i7 @ 2.93Ghz) on Vista64.

    My solution is in C, but I am not a professional C programmer. Feel free to criticize the algorithm and the code itself :)

    #include<stdio.h>
    #include<math.h>
    #include<stdlib.h>
    #include<time.h>
    
    //5MB... allocate a lot of memory at once each time we need it
    #define ARRAYMULT 5242880 
    
    
    //list of calculated primes
    __int64* primes; 
    //number of primes calculated
    __int64 primeCount;
    //the current size of the array
    __int64 arraySize;
    
    //Prints all of the calculated primes
    void PrintPrimes()
    {
        __int64 i;
        for(i=0; i<primeCount; i++)
        {
            printf("%d ", primes[i]);
        }
    
    }
    
    //Calculates all prime numbers to max
    void CalcPrime(__int64 max)
    {
        register __int64 i;
        double square;
        primes = (__int64*)malloc(sizeof(__int64) * ARRAYMULT);
        primeCount = 0;
        arraySize = ARRAYMULT;
    
        //we provide the first prime because its even, and it would be convenient to start
        //at an odd number so we can skip evens.
        primes[0] = 2;
        primeCount++;
    
    
    
        for(i=3; i<max; i+=2)
        {
            int j;
            square = sqrt((double)i);
    
            //only test the current candidate against other primes.
            for(j=0; j<primeCount; j++)
            {
                //prime divides evenly into candidate, so we have a non-prime
                if(i%primes[j]==0)
                    break;
                else
                {
                    //if we've reached the point where the next prime is > than the square of the
                    //candidate, the candidate is a prime... so we can add it to the list
                    if(primes[j] > square)
                    {
                        //our array has run out of room, so we need to expand it
                        if(primeCount >= arraySize)
                        {
                            int k;
                            __int64* newArray = (__int64*)malloc(sizeof(__int64) * (ARRAYMULT + arraySize));
    
                            for(k=0; k<primeCount; k++)
                            {
                                newArray[k] = primes[k];
                            }
    
                            arraySize += ARRAYMULT;
                            free(primes);
                            primes = newArray;
                        }
                        //add the prime to the list
                        primes[primeCount] = i;
                        primeCount++;
                        break;
    
                    }
                }
    
            }
    
        }
    
    
    }
    int main()
    {
        int max;
        time_t t1,t2;
        double elapsedTime;
    
        printf("Enter the max number to calculate primes for:\n");
        scanf_s("%d",&max);
        t1 = time(0);
        CalcPrime(max);
        t2 = time(0);
        elapsedTime = difftime(t2, t1);
        printf("%d Primes found.\n", primeCount);
        printf("%f seconds elapsed.\n\n",elapsedTime);
        //PrintPrimes();
        scanf("%d");
        return 1;
    }
    
    0 讨论(0)
  • 2020-12-05 15:48

    I decided to try this in F#, my first decent attempt at it. Using the Sieve of Eratosthenes on my 2.2Ghz Core 2 Duo it runs through 2..150,000 in about 200 milliseconds. Each time it calls it self it's eliminated the current multiples from the list, so it just gets faster as it goes along. This is one of my first tries in F# so any constructive comments would be appreciated.

    let max = 150000
    let numbers = [2..max]
    let rec getPrimes sieve max =
        match sieve with
        | [] -> sieve
        | _ when sqrt(float(max)) < float sieve.[0] -> sieve
        | _ -> let prime = sieve.[0]
               let filtered = List.filter(fun x -> x % prime <> 0) sieve // Removes the prime as well so the recursion works correctly.
               let result = getPrimes filtered max
               prime::result        // The filter removes the prime so add it back to the primes result.
    
    let timer = System.Diagnostics.Stopwatch()
    timer.Start()
    let r = getPrimes numbers max
    timer.Stop()
    printfn "Primes: %A" r
    printfn "Elapsed: %d.%d" timer.Elapsed.Seconds timer.Elapsed.Milliseconds
    
    0 讨论(0)
  • 2020-12-05 15:49

    Here's my contribution:

    Machine: 2.4GHz Quad-Core i7 w/ 8GB RAM @ 1600MHz

    Compiler: clang++ main.cpp -O3

    Benchmarks:

    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 100
    
    Calculated 25 prime numbers up to 100 in 2 clocks (0.000002 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 1000
    
    Calculated 168 prime numbers up to 1000 in 4 clocks (0.000004 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 10000
    
    Calculated 1229 prime numbers up to 10000 in 18 clocks (0.000018 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 100000
    
    Calculated 9592 prime numbers up to 100000 in 237 clocks (0.000237 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 1000000
    
    Calculated 78498 prime numbers up to 1000000 in 3232 clocks (0.003232 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 10000000
    
    Calculated 664579 prime numbers up to 10000000 in 51620 clocks (0.051620 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 100000000
    
    Calculated 5761455 prime numbers up to 100000000 in 918373 clocks (0.918373 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 1000000000
    
    Calculated 50847534 prime numbers up to 1000000000 in 10978897 clocks (10.978897 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ ./a.out 4000000000
    
    Calculated 189961812 prime numbers up to 4000000000 in 53709395 clocks (53.709396 seconds).
    Caelans-MacBook-Pro:Primer3 Caelan$ 
    

    Source:

    #include <iostream> // cout
    #include <cmath> // sqrt
    #include <ctime> // clock/CLOCKS_PER_SEC
    #include <cstdlib> // malloc/free
    
    using namespace std;
    
    int main(int argc, const char * argv[]) {
        if(argc == 1) {
            cout << "Please enter a number." << "\n";
            return 1;
        }
        long n = atol(argv[1]);
        long i;
        long j;
        long k;
        long c;
        long sr;
        bool * a = (bool*)malloc((size_t)n * sizeof(bool));
    
        for(i = 2; i < n; i++) {
            a[i] = true;
        }
    
        clock_t t = clock();
    
        sr = sqrt(n);
        for(i = 2; i <= sr; i++) {
            if(a[i]) {
                for(k = 0, j = 0; j <= n; j = (i * i) + (k * i), k++) {
                    a[j] = false;
                }
            }
        }
    
        t = clock() - t;
    
        c = 0;
        for(i = 2; i < n; i++) {
            if(a[i]) {
                //cout << i << " ";
                c++;
            }
        }
    
        cout << fixed << "\nCalculated " << c << " prime numbers up to " << n << " in " << t << " clocks (" << ((float)t) / CLOCKS_PER_SEC << " seconds).\n";
    
        free(a);
    
        return 0;
    }
    

    This uses the Sieve of Erastothenes approach, I've optimised it as much as I can with my knowledge. Improvements welcome.

    0 讨论(0)
  • 2020-12-05 15:51

    C#

    Enhancement to Aistina's code:

    This makes use of the fact that all primes greater than 3 are of the form 6n + 1 or 6n - 1.

    This was about a 4-5% speed increase over incrementing by 1 for every pass through the loop.

    class Program
    {       
        static void Main(string[] args)
        {
            DateTime start = DateTime.Now;
    
            int count = 2; //once 2 and 3
    
            int i = 5;
            while (count < 150000)
            {
                if (IsPrime(i))
                {
                    count++;
                }
    
                i += 2;
    
                if (IsPrime(i))
                {
                    count++;
                }
    
                i += 4;
            }
    
            DateTime end = DateTime.Now;
    
            Console.WriteLine("Total time taken: " + (end - start).TotalSeconds.ToString() + " seconds");
            Console.ReadLine();
        }
    
        static bool IsPrime(int n)
        {
            //if (n < 4)
            //return true;
            //if (n % 2 == 0)
            //return false;
    
            int s = (int)Math.Sqrt(n);
            for (int i = 2; i <= s; i++)
                if (n % i == 0)
                    return false;
    
            return true;
        }
    }
    
    0 讨论(0)
提交回复
热议问题