Prime Number Algorithm

前端 未结 7 1986
梦如初夏
梦如初夏 2020-12-19 05:14

Can anyone tell me how to implement Sieve of Eratosthenes algorithm in C? I need to generate prime numbers but my algorithm is slow.

My code:

#inclu         


        
7条回答
  •  没有蜡笔的小新
    2020-12-19 06:13

    Marc B's link shows a nice and simple algorithm which is correct, written by NSLogan. I wrote a slight modification to it to show some size/speed tradeoffs. I thought I'd share for interest's sake.

    First, the code:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define USE_BITS
    
    #ifdef USE_BITS
    #define alloc_prime char *prime = calloc(i/8+1,sizeof(*prime));
    #define set_not_prime(x) prime[x/8]|= (1<<(x%8))
    #define is_prime(x) (!(prime[x/8]&(1<<(x%8))))
    #endif
    
    #ifdef USE_CHAR
    #define alloc_prime char *prime = calloc(i+1,sizeof(*prime));
    #define set_not_prime(x) prime[x] = 1
    #define is_prime(x) (prime[x] == 0)
    #endif
    
    #ifdef USE_SIZE_TYPE
    #define alloc_prime size_t *prime = calloc(i+1,sizeof(*prime));
    #define set_not_prime(x) prime[x] = 1
    #define is_prime(x) (prime[x] == 0)
    #endif
    
     
    int main(){
        int i;
        printf("Find primes up to: ");
        scanf("%i",&i);
     
        clock_t start, stop;
        double t = 0.0;
           
        assert((start = clock())!=-1);
           
        //create prime list
        alloc_prime;
        int c1, c2, c3;
        if(!prime){
        printf("Can't allocate %zu bytes.\n",i*sizeof(*prime));
        exit(1);
        }
           
        //set 0 and 1 as not prime
        set_not_prime(0);
        set_not_prime(1);
    
        //find primes then eliminate their multiples (0 = prime, 1 = composite)
        for(c2 = 2;c2 <= (int)sqrt(i)+1;c2++){
          if(is_prime(c2)){
            c1=c2;
            for(c3 = 2*c1;c3 <= i+1; c3 += c1){
              set_not_prime(c3);
            }
          }
        }
           
        stop = clock();
        t = (double) (stop-start)/CLOCKS_PER_SEC;
           
        //print primes
        for(c1 = 0; c1 < i+1; c1++){
            if(is_prime(c1))printf("%i\n",c1);
        }
        printf("Run time: %f\n", t); //print time to find primes
    
        return 0;
    }
    

    Since this uses sqrt, to compile use: gcc prime.c -lm

    I've compared three different ways of storing the boolean variables that peoro suggested. One method actually uses bits, the second takes an entire byte, and the last uses an entire machine word. A naive guess about which is fastest might be the machine word method, since each flag/boolean is dealt with more 'naturally' by your machine. The timings to calculate the primes up to 100,000,000 on my machine were as follows:

    Bits: 3.8s Chars: 5.8s M-words: 10.8s

    It is interesting to note that even all the ugly bit-shifting necessary to represent a boolean with only one bit is still faster overall. My conjecture is that caching and locality-of-reference seem to outweigh the extra ~3 instructions. Plus, you end up using 1/nth the memory of the n-bit-machine-word method!

提交回复
热议问题