How to optimize/ make this c code even faster? - c

I need to optimize this c code in order for it to run as fast as possible. I am quite new to code optimization in general. What should I begin with?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char*argv[]) {
int n, i, flag;
int sumOfPrimeNumbers; //sum of prime numbers
sumOfPrimeNumbers = 0;
do {
flag = 0;
scanf("%d", &n);
for(i=2;i < n;i++)
{
if(n%i==0) {
flag=1; // flag all non-prime numbers
break;
}
}
if(flag==0) {
sumOfPrimeNumbers = sumOfPrimeNumbers + n; // sum prime numbers
}
} while (n != 0);
printf("%d\n", sumOfPrimeNumbers);
return 0;
}

For small values of n (maybe values less than 66536?) you can use a table of precomputed answers, like "printf("%d\n", table[n]);".
For larger values you can split n into "zone" and "offset in zone", like "zone = n / zone_size; offset = n % zone_size;" and then use "zone" as an index into a precomputed table to determine an initial starting point (and skip a huge amount of work, like "sumOfPrimeNumbers = zoneStartTable[n / zone_size;"). The "offset in zone" part can be used with Sieve of Eratosthenes; which means that it's nicer for "zone_size" to be the product of the smallest primes (e.g. maybe like "zone_size = 2 * 3 * 5 * 7 * 11 * 13 * 17;") because that makes it a little easier to create a Sieve of Eratosthenes from a non-zero starting point.
For this approach to work you will actually need 2 sieves - one to find primes from 1 to "sqrt(n)" so that you can mark multiples of those primes as "not prime" in the second sieve (which will contain values from "zone * zone_size" to n). This process can be accelerated by recognizing that the sieve for the smallest primes (that you used to determine "zone_size") create a pattern that repeats every "zone_size" numbers, and that pattern can be predetermined and then copied into both of the sieves to initialize the sieves, allowing you to skip marking the smallest primes in both sieves.

Improve the algorithm. Avoid premature optimizations
Rather than test up to n, search to the square root of n
// for(i=2;i < n;i++)
for (i=2; i <= n/i; i++)
Sieve of Eratosthenes
Form a list of found primes {2,3,5} and only test against those. As a new prime is found, append it to the list.
Many other optimizations possible.

Related

Matchmaking program in C?

The problem I am given is the following:
Write a program to discover the answer to this puzzle:"Let's say men and women are paid equally (from the same uniform distribution). If women date randomly and marry the first man with a higher salary, what fraction of the population will get married?"
From this site
My issue is that it seems that the percent married figure I am getting is wrong. Another poster asked this same question on the programmers exchange before, and the percentage getting married should be ~68%. However, I am getting closer to 75% (with a lot of variance). If anyone can take a look and let me know where I went wrong, I would be very grateful.
I realize, looking at the other question that was on the programmers exchange, that this is not the most efficient way to solve the problem. However, I would like to solve the problem in this manner before using more efficient approaches.
My code is below, the bulk of the problem is "solved" in the test function:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRAY_SIZE 100
#define MARRIED 1
#define SINGLE 0
#define MAX_SALARY 1000000
bool arrayContains(int* array, int val);
int test();
int main()
{
printf("Trial count: ");
int trials = GetInt();
int sum = 0;
for(int i = 0; i < trials; i++)
{
sum += test();
}
int average = (sum/trials) * 100;
printf("Approximately %d %% of the population will get married\n", average / ARRAY_SIZE);
}
int test()
{
srand(time(NULL));
int femArray[ARRAY_SIZE][2];
int maleArray[ARRAY_SIZE][2];
// load up random numbers
for (int i = 0; i < ARRAY_SIZE; i++)
{
femArray[i][0] = (rand() % MAX_SALARY);
femArray[i][1] = SINGLE;
maleArray[i][0] = (rand() % MAX_SALARY);
maleArray[i][1] = SINGLE;
}
srand(time(NULL));
int singleFemales = 0;
for (int k = 0; k < ARRAY_SIZE; k++)
{
int searches = 0; // count the unsuccessful matches
int checkedMates[ARRAY_SIZE] = {[0 ... ARRAY_SIZE - 1] = ARRAY_SIZE + 1};
while(true)
{
// ARRAY_SIZE - k is number of available people, subtract searches for people left
// checked all possible mates
if(((ARRAY_SIZE - k) - searches) == 0)
{
singleFemales++;
break;
}
int randMale = rand() % ARRAY_SIZE; // find a random male
while(arrayContains(checkedMates, randMale)) // ensure that the male was not checked earlier
{
randMale = rand() % ARRAY_SIZE;
}
checkedMates[searches] = randMale;
// male has a greater income and is single
if((femArray[k][0] < maleArray[randMale][0]) && (maleArray[randMale][1] == SINGLE))
{
femArray[k][1] = MARRIED;
maleArray[randMale][1] = MARRIED;
break;
}
else
{
searches++;
continue;
}
}
}
return ARRAY_SIZE - singleFemales;
}
bool arrayContains(int* array, int val)
{
for(int i = 0; i < ARRAY_SIZE; i++)
{
if (array[i] == val)
return true;
}
return false;
}
In the first place, there is some ambiguity in the problem as to what it means for the women to "date randomly". There are at least two plausible interpretations:
You cycle through the unmarried women, with each one randomly drawing one of the unmarried men and deciding, based on salary, whether to marry. On each pass through the available women, this probably results in some available men being dated by multiple women, and others being dated by none.
You divide each trial into rounds. In each round, you randomly shuffle the unmarried men among the unmarried women, so that each unmarried man dates exactly one unmarried woman.
In either case, you must repeat the matching until there are no more matches possible, which occurs when the maximum salary among eligible men is less than or equal to the minimum salary among eligible women.
In my tests, the two interpretations produced slightly different statistics: about 69.5% married using interpretation 1, and about 67.6% using interpretation 2. 100 trials of 100 potential couples each was enough to produce fairly low variance between runs. In the common (non-statistical) sense of the term, for example, the results from one set of 10 runs varied between 67.13% and 68.27%.
You appear not to take either of those interpretations, however. If I'm reading your code correctly, you go through the women exactly once, and for each one you keep drawing random men until either you find one that that woman can marry or you have tested every one. It should be clear that this yields a greater chance for women early in the list to be married, and that order-based bias will at minimum increase the variance of your results. I find it plausible that it also exerts a net bias toward more marriages, but I don't have a good argument in support.
Additionally, as I wrote in comments, you introduce some bias through the way you select random integers. The rand() function returns an int between 0 and RAND_MAX, inclusive, for RAND_MAX + 1 possible values. For the sake of argument, let's suppose those values are uniformly distributed over that range. If you use the % operator to shrink the range of the result to N possible values, then that result is still uniformly distributed only if N evenly divides RAND_MAX + 1, because otherwise more rand() results map to some values than map to others. In fact, this applies to any strictly mathematical transformation you might think of to narrow the range of the rand() results.
For the salaries, I don't see why you even bother to map them to a restricted range. RAND_MAX is as good a maximum salary as any other; the statistics gleaned from the simulation don't depend on the range of salaries; but only on their uniform distribution.
For selecting random indices into your arrays, however, either for drawing men or for shuffling, you do need a restricted range, so you do need to take care. The best way to reduce bias in this case is to force the random numbers drawn to come from a range that is evenly divisible by the number of options by re-drawing as many times as necessary to ensure it:
/*
* Returns a random `int` in the half-open interval [0, upper_bound).
* upper_bound must be positive, and should not exceed RAND_MAX + 1.
*/
int random_draw(int upper_bound) {
/* integer division truncates the remainder: */
int rand_bound = (RAND_MAX / upper_bound) * upper_bound;
for (;;) {
int r = rand();
if (r < rand_bound) {
return r % upper_bound;
}
}
}

spoj.com prime generator time limit exceeded

Getting time limit exceeded on submitting answer. I am also facing same problem with 2-3 more questions that I have submitted on spoj.com.
http://www.spoj.com/problems/PRIME1/
Peter wants to generate some prime numbers for his cryptosystem. Help him! Your task is to generate all prime numbers between two given numbers!
Input
The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n (1 <= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output
For every test case print all prime numbers p such that m <= p <= n, one number per line, test cases separated by an empty line.
Example
Input:
2
1 10
3 5
Output:
2
3
5
7
3
5
Warning: large Input/Output data, be careful with certain languages (though most should be OK if the algorithm is well designed)
Here is my code in C.
#include <stdio.h>
int main()
{
int t,i,k,count;
long long int j=0,m=0,n=0;
scanf("%d",&t);
for(i=1;i<=t;i++)
{
scanf("%lld%lld",&m,&n);
for(j=m;j<=n;j++)
{
count=0;
for(k=1;k<=j/2;k++)
{
if(j%k==0)
count++;
if(count>1)
break;
}
if(count==1)
printf("%lld\n",j);
}
printf("\n");
}
return 0;
}
Your algorithm is O((m-n)*n) which of course won't run within the allocated time limit. Let's go over your code:
count=0;
for(k=1;k<=j/2;k++)
{
if(j%k==0)
count++;
if(count>1)
break;
}
if(count==1)
printf("%lld\n",j);
Micro optimization: Why do you need a counter? You could get away with a bool.
Optimization: Why are you testing primes j/2? If j has a divisor greater than 1 than it's guaranteed that j has a divisor that's at most sqrt(j).
Micro Optimization: Don't consider even numbers at all, except for 2.
bool prime = j==2 || j%2==1 ;
for(k=2;prime && k*k<=j;k++)
{
if(j%k==0) prime = false;
}
}
if(prime) printf("%lld\n",j);
Now this is O((m-n)*sqrt(n)) which is a lot faster.
I suppose this won't make the limit. You could extend the second micro-optimization to skip numbers divisible by 3 very easy.
Optimization: If this is still not enough then you have to do a pseudo-primality test. One test that's very easy to implement in O(log(n)) is https://en.wikipedia.org/wiki/Fermat_primality_test. With this the complexity is down to O((m-n)*log(n)) which should be run in the available time limit.

Reducing memory usage when designing a sieve of eratosthenes in C

I'm trying to design a sieve of eratosthenes in C but I've run into two strange problems which I can't figure out. Here's my basic program outline. Ask users to set a range to display primes from. If the range minimum is below 9, set the minimum as 9. Fill an array with all odd numbers in the range.
1) I'm trying to reduce memory usage by declaring variable size arrays like so:
if (max<=UINT_MAX)
unsigned int range[(max-min)/2];
else if (max<=ULONG_MAX)
unsigned long int range[(max-min)/2];
else if (max<=ULLONG_MAX)
unsigned long long int range[(max-min)/2];
Why doesn't this compile? Variables min and max are declared as ints earlier and limits.h is included. I've commented out the selection structure and just declared unsigned long long int range[(max-min)/2]; for now which compiles and works for now.
2) My code runs but it sometimes marks small primes as non primes.
#include<stdio.h>
#include<limits.h>
void prime(int min, int max)
{
int i, f=0;
//declare variable size array
/*if (max<=(int)UINT_MAX)
unsigned int range[(max-min)/2];
else if (max<=(int)ULONG_MAX)
unsigned long int range[(max-min)/2];
else if (max<=(int)ULLONG_MAX)*/
unsigned long long int range[(max-min)/2];
//fill array with all odd numbers
if (min%2==0)
{
for (i=min+1;i<=max;i+=2)
{
range[f]=i;
f+=1;
}
}
else
{
for (i=min;i<=max;i+=2)
{
range[f]=i;
f+=1;
}
}
//assign 0 to cell if divisible by any number other than itself
for (i=3;i<=sqrt(max);++i)
{
for (f=0;f<=((max-min)/2);f++)
{
if (range[f]%i==0 && f!=i)
range[f]=0;
}
}
//troubleshoot only: print full range
for (f=0;f<=((max-min)/2);f++)
{
printf("ALL: %d / %d\n", f, range[f]);
}
//display all primes
if (min==9) /*print primes lower than 9 for ranges where min<9*/
printf("2\n3\n5\n7\n");
for (f=0;f<=((max-min)/2);f++) /*print non 0 numbers in array*/
{
if (range[f]!=0)
printf("%d\n", range[f]);
}
}
int main(void)
{
int digits1, digits2;
printf("\n\n\nCalculate Prime Numbers\n");
printf("This program will display all prime numbers in a given range. \nPlease set the range.\n");
printf("Minimum: ");
scanf("%d", &digits1);
if (digits1<9)
digits1=9;
printf("Maximum: ");
scanf("%d", &digits2);
printf("Calculating...");
printf("All prime numbers between %d and %d are:\n", digits1, digits2);
prime(digits1, digits2);
getchar();
getchar();
}
For example, if digits=1 and digits2=200 my program outputs all primes between 1 and 200 except 11 and 13. 11 and 13 are sieved out and I can't figure out why this happens to more and more low numbers as digits2 is increased.
3) Finally, is my sieve a proper sieve of eratosthenes? It kind of works but I feel like there is a more efficient way of sieving out non primes but I can't figure out how to implement it. One of my goals for this program is to be as efficient as possible. Again, what I have right now is:
//assign 0 to cell if divisible by any number other than itself
for (i=3;i<=sqrt(max);++i)
{
for (f=0;f<=((max-min)/2);f++)
{
if (range[f]%i==0 && f!=i)
range[f]=0;
}
}
Thanks for reading all of that! I'm sorry for posting yet another sieve of eratosthenes related question and thank you in advance for the help!
No, it is not a proper sieve of Eratosthenes. No testing of remainders is involved in the sieve of Eratosthenes algorithm, Wikipedia is real clear on this I think. :) The whole point to it is to avoid the trial divisions, to get the primes for free, without testing.
How? By generating their multiples, from every prime that we identify, in ascending order one after another.
The multiples of a prime p are: 2p, 2p + p, 2p + p + p, ...
The odd multiples of a prime p are: 3p, 3p + 2p, 3p + 2p + 2p, ...
As we enumerate them, we mark them in the sieve array. Some will be marked twice or more, e.g. 15 will be marked for 3 and for 5 (because 3 * 5 == 5 * 3). Thus, we can start enumerating and marking from p2:
for( i=3; i*i < n; i += 2 )
if( !sieve[i] ) // if `i` is not marked as composite
for( j = i*i; j < n; j += 2*i )
{
sieve[j] = 1; // 1 for composite, initially all are 0s
}
The key to the sieve is this: we don't store the numbers in the array. It is not an array of INTs; it is an array of 1-bit flags, 0 or 1 in value. The index of an entry in the sieve array signifies the number for which the sieve holds its status: marked, i.e. composite, or not yet marked, i.e. potentially prime.
So in the end, all the non-marked entries signify the primes. You will need to devise an addressing scheme of course, e.g. an entry at index i might correspond to the number a + 2*i where a is the odd start of the range. Since your range starts at some offset, this scheme is known as offset sieve of Eratosthenes. A skeleton C implementation is here.
To minimize the memory use, we need to treat our array as a bit array. In C++ e.g. it is easy: we declare it as vector<bool> and it is automatically bit-packed for us. In C we'll have to do some bit packing and unpacking ourselves.
A word of advice: don't go skimpy on interim variables. Name every meaningful entity in your program. There shouldn't be any (max-min)/2 in your code; but instead define width = max - min and use that name. Leave optimizations in the small to the compiler. :)
To your first question: it's a scope thing. Your code is equivalent to
if (max<=UINT_MAX)
{ unsigned int range[(max-min)/2]; } // note the curly braces!
else if (max<=ULONG_MAX)
{ unsigned long int range[(max-min)/2]; }
else if (max<=ULLONG_MAX)
{ unsigned long long int range[(max-min)/2]; }
so there's three range array declarations here, each in its own scope, inside the corresponding block. Each is created on entry to its enclosing block ({) and is destroyed on exit from it (}). In other words, it doesn't exist for the rest of your prime function anymore. Practically it means that if you declare your variable inside an if block, you can only use it inside that block (between the corresponding braces { and } ).
Q1: you can not declare a symbol (here: range) twice in the same scope. It is not exactly your problem but you are trying to do this: you declare range within the if scope and it is not visible outside.

Sorting integers based on their prime factors

I am kind of stuck how to sort integers based on their greatest prime factor in ascending order. For example, we have 3 and 8. The order should be: 8, 3 because 8's prime factor (2) is less than 3's prime factor (3). If we have the same greatest prime factor for 2 numbers like 9 and 27, then the smaller number should be first. In this order: 9, 27
Okay, here's my code, but it needs some modification.
long long sort(long long integers[], long long primes[]) {
/* loop variables */
int i, j;
/* temporary variable */
long long tmp;
for (i = (SIZE - 1); i > 0; i--) {
for (j = 1; j <= i; j++) {
if (integers[j-1] > integers[j]) {
tmp = integers[j-1];
integers[j-1] = integers[j];
integers[j] = tmp;
}
}
}
}
It is also important to mention that integers[i]'s greatest prime factor is stored as primes[i]. Primes are already all set up and good, this thing only needs correct sorting.
I hope you can help me.
Thanks. :)
Surely you just need to use primes somewhere. In your current code you aren't using that variable at all, and it seems rather clear where it should go.
Bonus tip: look up the standard C library function qsort.

Time complexity of the program

#include<stdio.h>
#include<time.h>
int main()
{
clock_t start;
double d;
long int n,i,j;
scanf("%ld",&n);
n=100000;
j=2;
start=clock();
printf("\n%ld",j);
for(j=3;j<=n;j+=2)
{
for(i=3;i*i<=j;i+=2)
if(j%i==0)
break;
if(i*i>j)
printf("\n%ld",j);
}
d=(clock()-start)/(double)CLOCKS_PER_SEC;
printf("\n%f",d);
}
I got the running time of 0.015 sec when n=100000 for the above program.
I also implemented the Sieve of Eratosthenes algorithm in C and got the running time of 0.046 for n=100000.
How is my above algorithm faster than Sieve's algorithm that I have implemented.
What is the time complexity of my above program??
My sieve's implementation
#define LISTSIZE 100000 //Number of integers to sieve<br>
#include <stdio.h>
#include <math.h>
#include <time.h>
int main()
{
clock_t start;
double d;
long int list[LISTSIZE],i,j;
int listMax = (int)sqrt(LISTSIZE), primeEstimate = (int)(LISTSIZE/log(LISTSIZE));
for(int i=0; i < LISTSIZE; i++)
list[i] = i+2;
start=clock();
for(i=0; i < listMax; i++)
{
//If the entry has been set to 0 ('removed'), skip it
if(list[i] > 0)
{
//Remove all multiples of this prime
//Starting from the next entry in the list
//And going up in steps of size i
for(j = i+1; j < LISTSIZE; j++)
{
if((list[j] % list[i]) == 0)
list[j] = 0;
}
}
}
d=(clock()-start)/(double)CLOCKS_PER_SEC;
//Output the primes
int primesFound = 0;
for(int i=0; i < LISTSIZE; i++)
{
if(list[i] > 0)
{
primesFound++;
printf("%ld\n", list[i]);
}
}
printf("\n%f",d);
return 0;
}
There are a number of things that might influence your result. To be sure, we would need to see the code for your sieve implementation. Also, what is the resolution of the clock function on your computer? If the implementation does not allow for a high degree of accuracy at the millisecond level, then your results could be within the margin of error for your measurement.
I suspect the problem lies here:
//Remove all multiples of this prime
//Starting from the next entry in the list
//And going up in steps of size i
for(j = i+1; j < LISTSIZE; j++)
{
if((list[j] % list[i]) == 0)
list[j] = 0;
}
This is a poor way to remove all of the multiples of the prime number. Why not use the built in multiplication operator to remove the multiples? This version should be much faster:
//Remove all multiples of this prime
//Starting from the next entry in the list
//And going up in steps of size i
for(j = list[i]; j < LISTSIZE; j+=list[i])
{
list[j] = 0;
}
What is the time complexity of my above program??
To empirically measure the time complexity of your program, you need more than one data point. Run your program for multiple values of N, then make a graph of N vs. time. You can do this using a spreadsheet, GNUplot, or graph paper and pencil. You can also use software and/or plain old mathematics to find a polynomial curve that fits your data.
Non-empirically: much has been written (and lectured in computer science classes) about analyzing computational complexity. The Wikipedia article on computational complexity theory might provide some starting points for further reading.
Your sieve implementation is incorrect; that's the reason why it is so slow:
you shouldn't make it an array of numbers, but an array of flags (you may still use int as the data type, but char would do as well)
you shouldn't be using index shifts for the array, but list[i] should determine whether i is a prime or not (and not whether i+2 is a prime)
you should start the elimination with i=2
with these modifications, you should follow 1800 INFORMATION's advice, and cancel all multiples of i with a loop that goes in steps of i, not steps of 1
Just for your time complexity:
You have an outer loop of ~LISTMAX iterations and an inner loop of max. LISTSIZE iterations. This means your complexity is
O(sqrt(n)*n)
where n = listsize. It is actually a bit lower since the inner loop reduces it's count eacht time and is only run for each unknown number. But that's difficult to calculate. Since the O-Notation offers an upper bound, O(sqrt(n)*n) should be ok.
The behaviour is difficult to predict, but you should take into account that accessing the memory is not cheap... it's probably faster to just calculate it again for small primes.
Those run times are too small to be meaningful. The system clock resolution is not accurate to that kind of level.
What you should do to get accurate timing information is run your algorithm in a loop. Repeat it a few thousand times to get the run time up to at least a second, then you can divide the time by the number of loops.

Resources