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 ...
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).
And, after checking for 2, you only need to test odd values, so you can do: i += 2 instead of i++ (e.g. 3,5,7,9,11,13,15,17,29,...).
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:
https://primes.utm.edu/notes/faq/six.html
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
Related
/Write a program to determine the total number of prime numbers below 1000,000,000 have the sum of their digits equal to 14? Make sure the execution time is few seconds./
#include<stdio.h>
#include<math.h>
int main() {
int i, j, count = 0, temp = 0, n, ans = 0, tot = 0;
for (i = 1; i <= 1000000000; i++) {
for (j = 2; j <= i / 2; j++) {
if (i % j == 0) {
count++;
}
}
if (count == 0) {
n = i;
while (n != 0) {
temp = n % 10;
n = n / 10;
ans = ans + temp;
}
if (ans == 14) {
tot++;
printf("%d,", i);
}
ans = 0;
temp = 0;
}
count = 0;
}
// printf("%d:\n",tot);
return 0;
}
Two simply improvements (amongst other):
1: Rather than iterate to i/2, iterate to the square root of i - that is j*j <= i.** This is a huge speed-up.
2: Quit loop once a factor found.
// for(j=2;j<=i/2;j++) {
// if(i%j==0) {
// count++;
// }
//}
for(j=2;j<=i/j;j++) { // _much_ lower limit
if(i%j==0) {
count++;
break; // No need to find more factors: `i` is not a prime.
}
}
Functionality: Inside if(count==0), I'd expect ans == 0 before while(n!=0).
** Use j<=i/j to prevent overflow. A good compiler will see a nearby i%j and often perform both i/j, i%j for the time cost of one.
The digit-sum function could also use a early return like:
int dsum14(int n) {
int sum = 0;
for (; n; n /= 10)
if ((sum += n % 10) > 14)
return 0;
return sum == 14 ? 1 : 0;
}
But how to combine the (efficient) prime search and this sum condition?
int n, cnt = 0;
for (n = 3; n < 1000*1000*1000; n += 2)
if (n%3 && n%5 && dsum14(n) && n%7 && n%11 && n%13)
cnt++;
This gives 77469 in 1.5 seconds. With dsum() at either end of the logical chain it is almost double.
The && n%7 && n%11 && n%13 part would be replaced by a function using a list of primes up to about 32000 (square root of max).
...or you can optimize it to 0.1 seconds, by tweaking the digsum function.
There are "only" 575 three-digit numbers 000-999 with sum 14 or less. So I prepare them and combine three of them to get a 9-digit number. Generating them instead of filtering them.
The tail looks like:
920000021
920000201
920001011
920010011
920100011
920100101
920101001
921001001
931000001
total count: 22588
real 0m0.098s
user 0m0.100s
sys 0m0.002s
And the start:
59
149
167
239
257
293
347
383
419
Not 100% sure if it's correct, but the total count also seems reasonable.
It all relies on the given max of 1000 Mio. digsum_prime() uses it to build the candidate number from three (almost) equal parts.
Code:
#include <stdio.h>
#include <stdlib.h>
int parr[5000] = {3};
struct {
int tri, sum;
} ts[999];
void primarr(void) {
int maxn = 32000;
int i = 1;
for (int n = 5; n < maxn; n += 2)
for (int div = 3;; div += 2) {
if (!(n % div))
break;
if (div*div > n) {
parr[i++] = n;
break;
}
}
}
int isprime(int n) {
for(int i = 0;; i++) {
if (!(n % parr[i]))
return 0;
if (parr[i]*parr[i] > n)
return 1;
}
}
int dsum(int n) {
int sum = 0;
for (; n; n /= 10)
sum += n % 10;
return sum;
}
int tsarr(void) {
int i = 0;
for (int n = 0; n < 1000; n++) {
int digsum = dsum(n);
if (digsum <= 14) {
ts[i].tri = n;
ts[i].sum = digsum;
i++;
}
}
return i;
}
int digsum_prime() {
int cnt = 0;
int tslen = tsarr();
printf("tslen: %d\n", tslen);
int high, mid, low;
int sum, num;
for (high = 0; high < tslen; high++) {
if(ts[high].sum > 13)
continue;
for (mid = 0; mid < tslen; mid++) {
if(ts[mid].sum + ts[high].sum > 13)
continue;
sum = ts[mid].sum + ts[high].sum;
for (low = 0; low < tslen; low++)
if (ts[low].tri % 2)
if(ts[low].sum + sum == 14) {
num = ts[high].tri * 1000*1000
+ ts[mid] .tri * 1000
+ ts[low] .tri;
if (isprime(num)) {
cnt++;
printf("%d\n", num);
}
}
}
}
return cnt;
}
int main(void) {
primarr();
printf("total count: %d\n", digsum_prime());
}
Changing 13-13-14 to 3-3-4 (but same preparation part) gives an overview - in 0.005 s!
tslen: 575
13
31
103
211
1021
1201
2011
3001
10111
20011
20101
21001
100003
102001
1000003
1011001
1020001
1100101
2100001
10010101
10100011
20001001
30000001
101001001
200001001
total count: 25
real 0m0.005s
user 0m0.005s
sys 0m0.000s
Make sure the execution time is few seconds.
oops
But the limits of OP are well chosen: a naive approach takes several seconds.
I'm supposed to improve this code using multithreading to sum and count all prime numbers of one million randomly generated integers in less than 6 seconds. My professor did it in less than a second how do I do so I'm stuck.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
int isPrime(int num) {
int i;
for (i = 2; i < num; i++) {
if (num % i == 0) {
return 0;
}
}
return 1;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Too few arguments ");
printf("USAGE: ./primeCalc <prime pivot> <num of random numbers>");
exit(0);
}
int randomPivot = atoi(argv[1]);
int numOfRandomNumbers = atoi(argv[2]);
long sum = 0;
long primeCounter = 0;
//init rundom generator
int random = rand();
srand(randomPivot);
//generate random numbers
for (int i = 0; i < numOfRandomNumbers; i++) {
random = rand();
//check if the number is prime
if (isPrime(random)) {
//if do, add up it's sum, and increment counter
sum = sum + random;
primeCounter++;
}
}
//keep the out format as this!!
printf("%ld,%ld\n", sum, primeCounter);
exit(0);
}
I tried using this code but, for some reason, the output was wrong and it only used 1 core even though I used 3 threads.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
pthread_mutex_t lock;
long count1 = 0, count2 = 0, count3 = 0;
long sum1 = 0, sum2 = 0, sum3 = 0;
void *isPrime1(void *x) {
int i; int num = *(int*)x;
if (num < 2)
return NULL;
if (num == 2)
return NULL;
{
sum1 += num;
count1 += 1;
}
if (num % 2 == 0)
return NULL;
for (i = 3; i * i < num; i = i + 2) {
if (num % i == 0) {
return NULL;
}
}
sum1 += num;
count1 += 1;
return NULL;
}
void *isPrime2(void *x) {
int i;
int num = *(int*)x;
if (num < 2)
return NULL;
if (num == 2)
return NULL;
{
sum2 += num;
count2 += 1;
}
if (num % 2 == 0)
return NULL;
for (i = 3; i * i < num; i = i + 2) {
if (num % i == 0) {
return NULL;
}
}
sum2 += num;
count2 += 1;
return NULL;
}
void *isPrime3(void *x) {
int i;
int num = *(int*)x;
if (num < 2)
return NULL;
if (num == 2)
return NULL;
{
sum3 += num;
count3 += 1;
}
if (num % 2 == 0)
return NULL;
for (i = 3; i * i < num; i = i + 2) {
if (num % i == 0) {
return NULL;
}
}
sum3 += num;
count3 += 1;
return NULL;
}
int main(int argc, char *argv[]) {
if (pthread_mutex_init(&lock, NULL) != 0) {
printf("mutix init failed\n");
return 0;
}
pthread_t tids[3];
if (argc != 3) {
printf("Too few arguments ");
printf("USAGE: ./primeCalc <prime pivot> <num of random numbers>");
exit(0);
}
int randomPivot = atoi(argv[1]);
int numOfRandomNumbers = atoi(argv[2]);
//init rundom generator
int random = rand();
srand(randomPivot);
//generate random numbers
for (int i = 0; i < numOfRandomNumbers; i += 3) {
random = rand();
pthread_create((&tids[0]), NULL, isPrime1, &random);
random = rand();
pthread_create((&tids[1]), NULL, isPrime2, &random);
random = rand();
pthread_create((&tids[2]), NULL, isPrime3, &random);
}
for (int j = 0; j < 3; j++)
pthread_join(tids[j], NULL);
long sum = sum1 + sum2 + sum3;
long count = count1 + count2 + count3;
//keep the out format as this!!
printf("%ld,%ld\n", sum, count);
exit(0);
}
There is no need for threads to achieve your goal, all you need are small improvements to the isPrime() function:
test even numbers explicitly
only test odd numbers in the loop
stop the loop when i > num / i.
return 0 for 0 and 1
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int isPrime(int num) {
int i;
if ((num & 1) == 0)
return num == 2;
for (i = 3; i <= num / i; i += 2) {
if (num % i == 0)
return 0;
}
return num != 1;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Too few arguments\n");
printf("USAGE: ./primeCalc <prime pivot> <num of random numbers>\n");
exit(0);
}
int randomPivot = atoi(argv[1]);
int numOfRandomNumbers = atoi(argv[2]);
long sum = 0;
long primeCounter = 0;
srand(randomPivot); //init rundom generator
for (int i = 0; i < numOfRandomNumbers; i++) {
int random = rand();
if (isPrime(random)) {
sum = sum + random;
primeCounter++;
}
}
printf("%ld,%ld\n", sum, primeCounter);
return 0;
}
Output on my 2015 slow laptop:
~/dev/stackoverflow > time ./primeCalc 0 1000000
50915866465059,48687
real 0m4.151s
user 0m4.119s
sys 0m0.011s
To further improve the performance, we can precompute the prime numbers less or equal to the square root of RAND_MAX, reducing the number of divisions for large prime numbers. Furthermore, the loop test can use a mutiplication as the prime factor candidates are all below square root of INT_MAX:
#include <stdio.h>
#include <stdlib.h>
static int primes[4793]; /* There are 4792 primes <= sqrt(0x7fffffff) */
int isPrime(int num) {
if ((num & 1) == 0)
return num == 2;
for (int *p = primes + 1; *p && (*p) * (*p) <= num; p++) {
if (num % *p == 0)
return 0;
}
return num != 1;
}
void initPrimes(int max) {
int i = 0, p;
primes[i++] = 2;
for (p = 3; p <= max / p; p += 2) {
if (isPrime(p))
primes[i++] = p;
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Too few arguments\n");
printf("USAGE: ./primeCalc <prime pivot> <num of random numbers>\n");
exit(0);
}
int randomPivot = atoi(argv[1]);
int numOfRandomNumbers = atoi(argv[2]);
long sum = 0;
long primeCounter = 0;
initPrimes(RAND_MAX);
srand(randomPivot); //init rundom generator
for (int i = 0; i < numOfRandomNumbers; i++) {
int random = rand();
if (isPrime(random)) {
sum = sum + random;
primeCounter++;
}
}
printf("%ld,%ld\n", sum, primeCounter);
return 0;
}
Output:
~/dev/stackoverflow > ./primeCalc1 0 1000000
50915866465059,48687
real 0m0.580s
user 0m0.566s
sys 0m0.004s
This result is consistent with your teacher's result, yet without threads.
You can further improve the timings using threads but there is a catch: for your test, you want to compute the same random numbers, which is not guaranteed if rand() is called from different threads. You thus need to compute the random numbers in the main thread and store them in an array, then use separate threads separate parts of the array and combine the results. I suggest you store the arguments and results in a separate structure for each thread and pass a pointer to it as the opaque argument.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static int primes[4793]; /* There are 4792 primes <= sqrt(0x7fffffff) */
int isPrime(int num) {
if ((num & 1) == 0)
return num == 2;
for (int *p = primes + 1; *p && (*p) * (*p) <= num; p++) {
if (num % *p == 0)
return 0;
}
return num != 1;
}
void initPrimes(int max) {
int i = 0, p;
primes[i++] = 2;
for (p = 3; p <= max / p; p += 2) {
if (isPrime(p))
primes[i++] = p;
}
}
struct primeCalcArgs {
pthread_t tid;
int *array;
int start, end;
long sum, count;
};
void *primeCalcTask(void *opaque) {
struct primeCalcArgs *p = opaque;
int *array = p->array;
p->sum = 0;
p->count = 0;
for (int i = p->start; i < p->end; i++) {
if (isPrime(array[i])) {
p->sum += array[i];
p->count++;
}
}
return NULL;
}
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "primeCalc: Too few arguments\n");
fprintf(stderr, "usage: ./primeCalc <prime pivot> <num of random numbers> [<nb of threads>]\n");
return 1;
}
int randomPivot = atoi(argv[1]);
int numOfRandomNumbers = atoi(argv[2]);
int numOfThreads = argc > 3 ? atoi(argv[3]) : 1;
long sum = 0;
long count = 0;
if (numOfThreads < 1)
numOfThreads = 1;
if (numOfRandomNumbers > 0) {
int i, n;
initPrimes(RAND_MAX);
int *array = malloc(sizeof(*array) * numOfRandomNumbers);
if (!array) {
fprintf(stderr, "primeCalc: cannot allocate random number array\n");
return 1;
}
srand(randomPivot); //init rundom generator
for (i = 0; i < numOfRandomNumbers; i++) {
array[i] = rand();
}
struct primeCalcArgs args[numOfThreads];
for (n = 0; n < numOfThreads; n++) {
args[n].array = array;
args[n].start = (long long)numOfRandomNumbers * n / numOfThreads;
args[n].end = (long long)numOfRandomNumbers * (n + 1) / numOfThreads;
args[n].sum = 0;
args[n].count = 0;
if (pthread_create(&args[n].tid, NULL, primeCalcTask, &args[n])) {
fprintf(stderr, "primeCalc: cannot create thread %d\n", n + 1);
break;
}
}
for (i = 0; i < n; i++) {
pthread_join(args[i].tid, NULL);
sum += args[i].sum;
count += args[i].count;
}
free(array);
}
printf("%ld,%ld\n", sum, count);
return 0;
}
Output:
~/dev/stackoverflow > time ./primeCalc 0 1000000
50915866465059,48687
real 0m0.581s
user 0m0.565s
sys 0m0.007s
~/dev/stackoverflow > time ./primeCalc 0 1000000 2
50915866465059,48687
real 0m0.293s
user 0m0.552s
sys 0m0.006s
~/dev/stackoverflow > time ./primeCalc 0 1000000 3
50915866465059,48687
real 0m0.286s
user 0m0.739s
sys 0m0.007s
~/dev/stackoverflow > time ./primeCalc 0 1000000 4
50915866465059,48687
real 0m0.242s
user 0m0.846s
sys 0m0.006s
~/dev/stackoverflow > time ./primeCalc 0 1000000 5
50915866465059,48687
real 0m0.245s
user 0m0.845s
sys 0m0.008s
~/dev/stackoverflow > time ./primeCalc 0 1000000 10
50915866465059,48687
real 0m0.281s
user 0m0.858s
sys 0m0.008s
~/dev/stackoverflow > time ./primeCalc 0 1000000 100
50915866465059,48687
real 0m0.279s
user 0m0.846s
sys 0m0.012s
~/dev/stackoverflow > time ./primeCalc 0 1000000 10000
50915866465059,48687
real 0m1.274s
user 0m0.752s
sys 0m1.663s
As you can see, my laptop has full 2 cores: the real time is exactly half for 2 threads. It gets marginal improvements from its hyper-threading capability for 3 and 4 threads but no improvement for more than 4 threads. Performance actually degrades for extra threads and I am even surprised that requesting 10000 threads succeeds and still performs reasonably well.
For larger counts of random numbers, I would suggest using a sieve to compute a bitmap of all primes up to RAND_MAX, adding a fixed overhead to the whole process. On my laptop, this sieve takes one or two seconds and makes the prime test immediate, leaving just the overhead of the random number generator.
I was trying to solve Project Euler question 16 using c. I did not use bignnum libraries. The question asks 2^1000. I decided to store every digit of that number in an array.
For Example: 45 means arr[0]=4, arr[1]=5;
The problem is definitely i the function int multi.
#include<stdio.h>
#include<conio.h>
int multi(int *base, int k);// does the multiplication of array term by 2
void switcher();//switches every term when the fore mostvalue is >10
int finder();// finds the array address of last value
int arr[1000];
int summer();//sums all values of the array
int main()
{
arr[1000] = { 0 };
arr[0] = 1;
int i, j, sum, k, p;
for (i = 0; i < 1000; i++)
{
j = 0;
k = finder();
p = multi(arr + k, j);
}
sum = summer();
printf("sum of digits of 2^1000 is %d", sum);
_getch();
}
int multi(int *base, int k)
{
int p;
if (base == arr)
{
*base = *base - 1;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
switcher();
}
return 0;
}
*base = *base * 2;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
p = multi(base - 1, 1);
}
else
{
p = multi(base - 1, 0);
}
}
void switcher()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
j--;
for (; j > 0; j--)
{
arr[j + 1] = arr[j];
}
arr[0] = 1;
}
int finder()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
return --j;
}
int summer()
{
int summ, i;
summ = 0;
for (i = 0; i<1000; i++)
{
summ = summ + arr[i];
if (arr[i] == 0)
break;
}
return summ;
}
It compiles but during runtime it shows Access Write Violation, base was ......
Please explain this error and how to resolve it ?
Array is of 100 Bytes but you are looping for 1000. Also in function Finder() , you do not have a limit on variable j so your array size is going beyond 100 bytes.
Also use memset to assign array variables to 0.
As said in the comments, 2^1000 has 302 decimal digits.
You're going far outside your array.
But your code is very complicated because you store the digits with the most significant one first.
Since you're only interested in the digits and not the order in which they would be written, you can store the number "in reverse", with the least significant digit first.
This makes the code much simpler, as you can loop "forwards" and no longer need to shuffle array elements around.
Using -1 as "end of number" marker, it might look like this:
void twice(int* digits)
{
int i = 0;
int carry = 0;
while (digits[i] >= 0)
{
digits[i] *= 2;
digits[i] += carry;
if (digits[i] >= 10)
{
carry = 1;
digits[i] -= 10;
}
else
{
carry = 0;
}
i++;
}
if (carry)
{
digits[i] = 1;
digits[i+1] = -1;
}
}
int main()
{
int digits[302] = {1, -1}; /* Start with 1 */
twice(digits); /* digits is now { 2, -1 } */
return 0;
}
#include <stdio.h>
#include <math.h>
int prime (long n);
long reverse(long n);
int main(void)
{
long n;
long i, j;
puts("Enter n dight number, and we will help you find symmetrical prime number");
scanf("%ld", &n);
for (i = 11; i < (pow(10, n) - 1); i+= 2)
{
if (prime(i))
{
j = reverse(i);
if (i == j)
{
printf("%ld\n", i);
}
}
}
}
int prime (long n) //estimate whether the number n is primer number
{
int status = 0;
int j;
//1 is prime, 0 is not
if (n % 2 == 0 || n == 3)
{
if (n == 2)
status = 1;
if (n == 3)
status = 1;
else
{
n++;
status = 0;
}
}
else
{
j = 3;
while (j <= sqrt(n))
{
if (n % j == 0)
{
status = 0;
break;
}
else
status = 1;
j+= 2;
}
}
return status;
}
long reverse(long n) //reverse a number
{
int i, j, x;
long k, sum;
int digit = 0;
int ar[1000];
while (n > 0)
{
k = n;
n = n / 10;
x = (k - n*10);
digit++;
ar[digit] = x;
}
for (i = 1,j = digit - 1; i <= digit; i++, j--)
{
sum += ar[i] * pow(10, j)
}
return sum;
}
I build a reverse function in order to reverse numbers, for example, 214, to 412.
This function works fine in individual number, for instance, I type reverse(214), it return 412, which is good. But when I combine reverse() function with for loop, this function can not work... it produces some strange number...
so How can I fix this problem?
The reverse function is extremely complicated. The better way to go about it would be:
long reverse (long n)
{
long result = 0;
while (n != 0)
{
result *= 10;
result += n % 10;
n /= 10;
}
return result;
}
I think the problem in your code is that in the following segment
digit++;
ar[digit] = x;
you first increment the position then assign to it, thus leaving ar[0] unintialized.
How can I fix this problem?
You need to initialize sum
long k, sum = 0;
^
See the code from #Armen Tsirunyan for a simpler approach.
I am trying to implement the sieve of eratosthenes in C. The code works for small input values, but once the input goes beyond a certain range, a run- time error is thrown. This is the second problem in the classical section of the SPOJ base. What is the mistake?
#include<stdio.h>
#include<math.h>
int prime(unsigned long int, unsigned long int);
int main()
{
int nitem;
unsigned long int sn,fn;
scanf("%d", &nitem);
while(nitem)
{
scanf("%lu", &fn);
//printf("%d",fn);
scanf("%lu", &sn);
prime(fn, sn);
nitem--;
}
return 0;
}
int prime(unsigned long int fn, unsigned long int sn)
{
unsigned long int prim[100000];
int i,j,k;
for(i = 0; i < 100000; i++)
{
prim[i] = 1;
}
prim[0] = 0;
prim[1] = 0;
//printf("%d", sn);
//printf("%d", k);
//printf("%d", (k <= sn));
for(k = 2; k <= sqrt(sn); k++)
{
// printf("alksnc%5d", k);
if(prim[k] == 1)
{
for(j = 2; (k * j) <= sn; j++)
{
//printf("%d", prim[k]);
prim[k * j] = 0;
}
}
}
for(int i = 0; i <= sn; i++)
{
if(prim[i] !=0 && i >= fn)
{
printf("%lu\n", i);
}
}
printf("\n");
return;
}
Input:
1
100000 100345
output:
run time error
Input:
1
3 5
output:
3
5
We can make more efficient use of memory (2x) by only sieving odd numbers as all the even numbers you're processing waste time and space. It's trickier to work out but gives us something like:
#include <math.h>
#include <libc.h>
#define MAX_ODD_PRIMES 1048576
void prime(unsigned long fn, unsigned long sn)
{
unsigned char primes[MAX_ODD_PRIMES];
for (unsigned long i = 0; i < MAX_ODD_PRIMES; i++)
{
primes[i] = TRUE;
}
primes[0] = 0; // preset first odd, '1'
for (unsigned long k = 3; k <= sqrt(sn) + 1; k += 2)
{
if (primes[k / 2])
{
for (unsigned long j = 3; (k * j) <= sn; j += 2)
{
primes[k * j / 2] = FALSE;
}
}
}
if (fn <= 2)
{
printf("2\n");
fn = 3;
}
for (unsigned long i = fn / 2; i * 2 + 1 <= sn; i++)
{
if (primes[i])
{
printf("%lu\n", i * 2 + 1);
}
}
}
EXAMPLE
> ./a.out
1 1999900 2000000
1999957
1999969
1999979
1999993
>
1) Array range error.
By changing code
for (j = 2; (k * j) <= sn; j++) {
if (k * j >= 100000) {
printf("Out of range %d %d\n", k, j);
exit(1);
}
prim[k * j] = 0;
}
}
With input 2, 100000
Output
Out of range 2 50000
By using an array (VLA) sized to the task, this is avoided. Many other optimizations available. Consider also a malloc() array.
void prime(unsigned long int fn, unsigned long int sn) {
unsigned long int prim[sn + 1];
2) int prime() eventually performs return; where return something; is expected. Suggest changing function to void prime()
int prime(unsigned long int fn, unsigned long int sn) {
unsigned long int prim[100000];
...
printf("\n");
return;
}