简体   繁体   中英

(spoj)prime generator using c- time limited exceeded issue?

My code is throwing time exceeded in spoj although it is executed correctly,

Here's my code:

#include <stdio.h>
 
int main() {
 
    int t;
    scanf("%d",&t);
    while(t--){
        long int n,m,count=0;
        scanf("%ld%ld",&n,&m);
        for(int i=n;i<=m;i++){
            count=0;
            for(int j=1;j<=i;j++){
                if(i%j==0){
                    count++;
                }
            }
            if(count==2){
                printf("%d\n",i);
            }
        }
    }
    return 0;
}

From my top comments, there are various speedups...

  1. The biggest issue is that you iterate by 1 until you reach m . This is much faster if you stop at the int equivalent of sqrt(m) .

  2. And, after checking for 2, you only need to test odd values, so you can do: i += 2 instead of i++ (eg 3,5,7,9,11,13,15,17,29,... ).

  3. And, after 3, primes are numbers that are only of the form: 6n-1 or 6n+1 . So, you can test [only] the sequence 5,7 11,13 17,19 23,25 29,31...

thank you for showing interest to solve my doubt could u please clearly explain from point to point

There are many references for the above speedups. For the first two, look at https://en.wikipedia.org/wiki/Trial_division

For (3), a web search on prime 6n produces:

  1. https://primes.utm.edu/notes/faq/six.html
  2. https://reflectivemaths.wordpress.com/2011/07/22/proof-primes-are-6n-1/

Note that [as others have mentioned], a "sieve" algorithm may be faster if you have sufficient memory: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes


Note that I first mentioned (1) (on SO) in a comment here: Finding Primes, where did I got wrong?

I had developed a benchmark program for successively faster algorithms for that question, but never got around to adding an answer.

Here is the program that I developed. Note that the function prime1 is equivalent to your algorithm.

// primebnc/primebnc.c -- prime algorithm benchmark

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//#define MAXCNT        10001
//#define MAXCNT        20002
//#define MAXCNT        30003
//#define MAXCNT        40004
#define MAXCNT      1000000

int opt_f;

typedef unsigned long long val_t;

typedef struct {
    int tst_no;                         // test number
    const char *tst_who;                // test description
    double tst_elap;                    // elapsed time for test
} tst_t;

int tstnocur;                           // current test number
int tstnobase;                          // lowest test number
int tstnomax;                           // highest test number
int inited;                             // 1=initialization complete
const char *reason;
tst_t tstlist[30];                      // list of test results

int pcntold;
double bestrate;
double tvprev;

int maxcnt;
val_t *pxold;
val_t *pxnow;

// iteratively get square root
#define SQR(_n) \
    for (;  (xsqrt * xsqrt) < _n;  xsqrt += 1)

// tstloc -- find test control for given test number
tst_t *
tstloc(int tstno)
{

    if (tstno == 0)
        tstno = tstnocur;

    return &tstlist[tstno];
}

// tstset -- setup test
void
tstset(int tstno,const char *tag)
{
    tst_t *tst;

    tstnocur = tstno;

    // remember lowest test number
    if (tstnobase == 0)
        tstnobase = tstno;

    // increase count of active tests
    if (tstno > tstnomax)
        tstnomax = tstno;

    reason = tag;

    tst = tstloc(tstno);
    tst->tst_no = tstno;
    tst->tst_who = reason;
}

int
prime1(val_t *primes)
{
    val_t i;
    int idx;
    int isprime;
    val_t n = 2;

    idx = 0;
    while (idx <= maxcnt) {
        isprime = 1;

        for (i = 2; i < n; i++) {
            if (n % i == 0) {
                isprime = 0;
                break;
            }
        }

        if (isprime) {
            primes[idx] = n;
            idx++;
        }

        n++;
    }

    tstset(1,"baseline 2 to n");

    return idx;
}

int
prime2(val_t *primes)
{
    val_t i;
    int idx;
    int isprime;
    val_t xsqrt;
    val_t n = 2;
    val_t n2;

    xsqrt = 0;

    idx = 0;
    primes[idx++] = 2;

    while (idx <= maxcnt) {
        // get sqrt(n)
        SQR(n);

        isprime = 1;

        for (i = 2; i <= xsqrt; i++) {
            if (n % i == 0) {
                isprime = 0;
                break;
            }
        }

        if (isprime) {
            primes[idx] = n;
            idx++;
        }

        n2 = n + 1;
        if (n2 < n)
            printf("overflow: idx=%d\n",idx);
        n = n2;
    }

    tstset(2,"2 to sqrt by 2");

    return idx;
}

int
prime3(val_t *primes)
{
    val_t i;
    int idx;
    int isprime;
    val_t xsqrt;
    val_t n;

    xsqrt = 0;

    idx = 0;
    primes[idx++] = 2;
    primes[idx++] = 3;
    n = 5;

    while (idx <= maxcnt) {
        // get sqrt(n)
        SQR(n);

        isprime = 1;
        for (i = 3; i <= xsqrt; i += 2) {
            if (n % i == 0) {
                isprime = 0;
                break;
            }
        }

        if (isprime) {
            primes[idx] = n;
            idx++;
        }

        n += 2;
    }

    tstset(3,"3 to sqrt by 2");

    return idx;
}

int
prime4(val_t *primes)
{
    val_t i;
    int idx;
    int isprime;
    val_t xsqrt;
    val_t n;
    val_t lo;
    val_t hi;

    xsqrt = 0;

    idx = 0;
    primes[idx++] = 2;
    primes[idx++] = 3;
    n = 6;

    while (idx <= maxcnt) {
        lo = n - 1;
        hi = n + 1;

        // get sqrt(n)
        SQR(hi);

        isprime = 3;
        for (i = 3;  i <= xsqrt;  i += 2) {
            if (isprime & 1) {
                if (lo % i == 0)
                    isprime &= ~1;
            }
            if (isprime & 2) {
                if (hi % i == 0)
                    isprime &= ~2;
            }
            if (! isprime)
                break;
        }

        if (isprime & 1) {
            primes[idx] = lo;
            idx++;
        }

        if (isprime & 2) {
            primes[idx] = hi;
            idx++;
        }

        n += 6;
    }

    tstset(4,"6 to sqrt by 6 (combined 6n-1/6n+1 loops)");

    return idx;
}

int
prime5(val_t *primes)
{
    val_t i;
    int idx;
    int isprime;
    val_t xsqrt;
    val_t n;
    val_t lo;
    val_t hi;

    xsqrt = 0;

    idx = 0;
    primes[idx++] = 2;
    primes[idx++] = 3;
    n = 6;

    while (idx <= maxcnt) {
        lo = n - 1;
        hi = n + 1;

        // get sqrt(n)
        SQR(hi);

        isprime = 1;
        for (i = 3; i <= xsqrt; i += 2) {
            if (lo % i == 0) {
                isprime = 0;
                break;
            }
        }
        if (isprime) {
            primes[idx] = lo;
            idx++;
        }

        isprime = 1;
        for (i = 3; i <= xsqrt; i += 2) {
            if (hi % i == 0) {
                isprime = 0;
                break;
            }
        }
        if (isprime) {
            primes[idx] = hi;
            idx++;
        }

        n += 6;
    }

    tstset(5,"6 to sqrt by 6 (separate 6n-1/6n+1 loops)");

    return idx;
}

int
prime6(val_t *primes)
{
    int cnt;
    int isprime;
    val_t xsqrt;
    val_t n;
    val_t lo;
    val_t hi;
    val_t pval;
    val_t *pptr;
    val_t *pend;

    xsqrt = 0;

    cnt = 0;
    primes[cnt++] = 2;
    primes[cnt++] = 3;
    n = 6;

    while (cnt <= maxcnt) {
        lo = n - 1;
        hi = n + 1;

        // get sqrt(n)
        SQR(hi);

        isprime = 3;
        pptr = primes;
        pend = primes + cnt;
        for (;  pptr < pend;  ++pptr) {
            pval = *pptr;

            // early stop if we exceed square root of number being tested
            if (pval > xsqrt)
                break;

            // test 6n - 1
            if (isprime & 1) {
                if ((lo % pval) == 0)
                    isprime &= ~1;
            }

            // test 6n + 1
            if (isprime & 2) {
                if ((hi % pval) == 0)
                    isprime &= ~2;
            }

            // bug out if both are non-prime
            if (! isprime)
                break;
        }

        // 6n - 1 is prime
        if (isprime & 1) {
            primes[cnt] = lo;
            cnt++;
        }

        // 6n + 1 is prime
        if (isprime & 2) {
            primes[cnt] = hi;
            cnt++;
        }

        n += 6;
    }

    tstset(6,"6 to sqrt by prime list (combined 6n-1/6n+1 loops)");

    return cnt;
}

int
prime7(val_t *primes)
{
    int cnt;
    int isprime;
    val_t xsqrt;
    val_t n;
    val_t lo;
    val_t hi;
    val_t pval;
    val_t *pptr;
    val_t *pend;

    xsqrt = 0;

    cnt = 0;
    primes[cnt++] = 2;
    primes[cnt++] = 3;
    n = 6;

    while (cnt <= maxcnt) {
        lo = n - 1;
        hi = n + 1;

        // get sqrt(n)
        SQR(hi);

        // check for 6n - 1 is prime
        isprime = 1;
        pptr = primes;
        pend = primes + cnt;
        for (;  pptr < pend;  ++pptr) {
            pval = *pptr;

            // early stop if we exceed square root of number being tested
            if (pval > xsqrt)
                break;

            // test 6n - 1
            if ((lo % pval) == 0) {
                isprime = 0;
                break;
            }
        }
        if (isprime) {
            primes[cnt] = lo;
            cnt++;
        }

        // check for 6n + 1 is prime
        isprime = 1;
        pptr = primes;
        pend = primes + cnt;
        for (;  pptr < pend;  ++pptr) {
            pval = *pptr;

            // early stop if we exceed square root of number being tested
            if (pval > xsqrt)
                break;

            // test 6n + 1
            if ((hi % pval) == 0) {
                isprime = 0;
                break;
            }
        }
        if (isprime) {
            primes[cnt] = hi;
            cnt++;
        }

        n += 6;
    }

    tstset(7,"6 to sqrt by prime list (separate 6n-1/6n+1 loops)");

    return cnt;
}

double
tscgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_REALTIME,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    return sec;
}

void
showrat(double ratio,int tstprev)
{
    const char *tag;

    if (ratio > 1.0)
        tag = "faster";
    else {
        tag = "slower";
        ratio = 1.0 / ratio;
    }

    printf(" %.3fx %s than prime%d\n",ratio,tag,tstprev);
}

void
timeit(int (*pfnc)(val_t *))
{
    tst_t *tstcur;
    tst_t *tstcmp;
    val_t *pnow;
    val_t *pold;
    int pcntact;
    double tvbeg;
    double tvend;
    double rate;
    double ratio;

    printf("---------------\n");

    pold = pxold;
    pnow = inited ? pxnow : pxold;

    // load up the cache
    for (int i = 0; i < maxcnt; i++)
        pnow[i] = 1;

    tvbeg = tscgetf();
    pcntact = pfnc(pnow);
    tvend = tscgetf();

    tvend -= tvbeg;

    tstcur = tstloc(0);

    printf("prime%d: %s\n",tstnocur,reason);

    // show prime generation rate
    rate = (double) maxcnt / tvend;
    printf(" %.9f (%.3f primes/sec)\n",tvend,rate);

    do {
        if (! inited) {
            pcntold = pcntact;
            bestrate = rate;
            break;
        }

        // show time ratio
        for (int tstno = tstnobase;  tstno <= tstnomax;  ++tstno) {
            if (tstno == tstnocur)
                continue;
            tstcmp = tstloc(tstno);
            ratio = tstcmp->tst_elap / tvend;
            showrat(ratio,tstno);
        }

        for (int i = 0; i < maxcnt; i++) {
            if (pnow[i] != pold[i]) {
                printf("%d: pold=%lld pnow=%lld\n",i,pold[i],pnow[i]);
                break;
            }
        }
    } while (0);

    tstcur->tst_elap = tvend;
    inited = 1;
}

int
main(int argc,char **argv)
{
    char *cp;

    --argc;
    ++argv;

    maxcnt = MAXCNT;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'f':
            opt_f = 1;
            break;
        case 'N':
            maxcnt = strtol(cp + 2,&cp,10);
            break;
        }
    }

    setlinebuf(stdout);

    if (opt_f)
        maxcnt = 40004;

    printf("maxcnt=%d\n",maxcnt);
    pxold = calloc(maxcnt + 1,sizeof(val_t));
    pxnow = calloc(maxcnt + 1,sizeof(val_t));

    // this takes a whole minute
    if (opt_f)
        timeit(prime1);

    // these are _much_ faster
    timeit(prime2);
    timeit(prime3);
    timeit(prime4);
    timeit(prime5);
    timeit(prime6);
    timeit(prime7);

    return 0;
}

Here is the program output with the -f option (to force invocation of prime1 ):

maxcnt=40004
---------------
prime1: baseline 2 to n
 69.242110729 (577.741 primes/sec)
---------------
prime2: 2 to sqrt by 2
 0.182171345 (219595.459 primes/sec)
 380.093x faster than prime1
---------------
prime3: 3 to sqrt by 2
 0.091353893 (437901.424 primes/sec)
 757.955x faster than prime1
 1.994x faster than prime2
---------------
prime4: 6 to sqrt by 6 (combined 6n-1/6n+1 loops)
 0.095818758 (417496.541 primes/sec)
 722.636x faster than prime1
 1.901x faster than prime2
 1.049x slower than prime3
---------------
prime5: 6 to sqrt by 6 (separate 6n-1/6n+1 loops)
 0.095270157 (419900.642 primes/sec)
 726.797x faster than prime1
 1.912x faster than prime2
 1.043x slower than prime3
 1.006x faster than prime4
---------------
prime6: 6 to sqrt by prime list (combined 6n-1/6n+1 loops)
 0.047716141 (838374.591 primes/sec)
 1451.126x faster than prime1
 3.818x faster than prime2
 1.915x faster than prime3
 2.008x faster than prime4
 1.997x faster than prime5
---------------
prime7: 6 to sqrt by prime list (separate 6n-1/6n+1 loops)
 0.040664196 (983764.685 primes/sec)
 1702.778x faster than prime1
 4.480x faster than prime2
 2.247x faster than prime3
 2.356x faster than prime4
 2.343x faster than prime5
 1.173x faster than prime6

Here is the program output without -f :

maxcnt=1000000
---------------
prime2: 2 to sqrt by 2
 24.093246222 (41505.407 primes/sec)
---------------
prime3: 3 to sqrt by 2
 12.029967308 (83125.745 primes/sec)
 2.003x faster than prime2
---------------
prime4: 6 to sqrt by 6 (combined 6n-1/6n+1 loops)
 12.633468866 (79154.824 primes/sec)
 1.907x faster than prime2
 1.050x slower than prime3
---------------
prime5: 6 to sqrt by 6 (separate 6n-1/6n+1 loops)
 12.002494335 (83316.015 primes/sec)
 2.007x faster than prime2
 1.002x faster than prime3
 1.053x faster than prime4
---------------
prime6: 6 to sqrt by prime list (combined 6n-1/6n+1 loops)
 4.346790791 (230054.780 primes/sec)
 5.543x faster than prime2
 2.768x faster than prime3
 2.906x faster than prime4
 2.761x faster than prime5
---------------
prime7: 6 to sqrt by prime list (separate 6n-1/6n+1 loops)
 3.761972904 (265817.970 primes/sec)
 6.404x faster than prime2
 3.198x faster than prime3
 3.358x faster than prime4
 3.190x faster than prime5
 1.155x faster than prime6

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM