Most efficient code for the first 10000 prime numbers?

前端 未结 30 1401
日久生厌
日久生厌 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:41

    The Sieve seems to be the wrong answer. The sieve gives you the primes up to a number N, not the first N primes. Run @Imran or @Andrew Szeto, and you get the primes up to N.

    The sieve might still be usable if you keep trying sieves for increasingly larger numbers until you hit a certain size of your result set, and use some caching of numbers already obtained, but I believe it would still be no faster than a solution like @Pat's.

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

    The following Mathcad code calculated the first million primes in under 3 minutes.

    Bear in mind that this would be using floating point doubles for all of the numbers and is basically interpreted. I hope the syntax is clear.

    enter image description here

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

    Since you want first 10000 primes only, rather than coding complex algorithm I'll suggest the following

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

    now call is prime as you need it

    for(int i=1 ; i<=1000 ; i++){
        if(isPrime(i)){
           //do something
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:43

    This is an old question, but there's something here everyone's missing...

    For primes this small, trial division isn't that slow... there are only 25 primes under 100. With so few primes to test, and such small primes, we can pull out a neat trick!

    If a is coprime to b, then gcd a b = 1. Coprime. Fun word. Means it doesn't share any prime factors. We can thus test for divisibility by several primes with one GCD call. How many? Well, the product of the first 15 primes is less than 2^64. And the product of the next 10 is also less than 2^64. That's all 25 that we need. But is it worth it?

    Let's see:

    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)
    

    A 6 fold improvement there.

    (length is to force the list to be computed. By default Haskell prints things 1 Unicode character at a time and so actually printing the list will either dominate the time or dominate the amount of actual code used.)

    Of course, this is running in GHCi - a repl running interpreted code - on an old laptop and it is not interpreting any of these numbers as int64s or even BigInts, nor will it even if you ask it to (well, you can force it, but it's ugly and doesn't really help). It is interpreting every single number there as generalized Integer-like things that can be specialized to some particular type via dictionary lookup, and it is traversing a linked list (which is not fused away here as it's not compiled) 3 times. Interestingly, hand fusing the two filters actually slows it down in the REPL.

    Let's compile it:

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

    Using the RTS report because Windows. Some lines trimmed because they aren't relevant - they were other GC data, or measurements of only part of the execution, and together add up to 0.004s (or less). It's also not constant folding, because Haskell doesn't actually do much of that. If we constant fold ourselves (main = print 10000), we get dramatically lower allocation:

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

    Literally just enough to load the runtime, then discover there's nothing to do but print a number and exit. Let's add wheel factorization:

    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)
    

    Cut down approximately 1/3rd relative to our reference of main = print 10000, but there's definitely room for more optimization. It actually stopped to perform a GC in there for example, while with tweaking there shouldn't be any heap use. For some reason, compiling for profiling here actually cuts the runtime down to 2 milliseconds:

    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)
    

    I'm going to leave this as is for now, I'm pretty sure random jitter is starting to dominate.

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

    Here is a Sieve of Eratosthenes that I wrote in PowerShell a few days ago. It has a parameter for identifying the number of prime numbers that should be returned.

    #
    # 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
    }
    
    0 讨论(0)
  • 2020-11-29 19:51

    I have been working on find primes for about a year. This is what I found to be the fastest:

    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 seconds to get to 2147483629 starting at 2.

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