spoj.com prime generator time limit exceeded - c

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.

Related

How to optimize/ make this c code even faster?

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.

Given that the inputs can be up to 1000000000, how can I write a more time and memory efficient program? (print all primes between m and n)

Here is the code below (ans to a CP qs)
The time limit for execution is 6 seconds but my code is slower than.
How can I make it more memory and time efficient ?
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.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
long int t,m,n,i,j,k;
//printf("Enter number of testcases:\n");
scanf("%ld",&t);
long int test[t][2];
for(i=0;i<t;i++){
//printf("Enter m,n:\n");
scanf("%ld %ld",&test[i][0],&test[i][1]);
}
for(k=0;k<t;k++){
for(i=test[k][0];i<=test[k][1];i++){
for(j=2;j*j<i*i;j++){
if(i%j==0)
break;
}
if(j==i){
printf("%ld\n",i);
}
}
printf("\n");
}
return 0;
}
Use offset sieve of Eratosthenes (see also this answer, with pseudocode; both links are to SO answers by me).
It is a segmented sieve of Eratosthenes modified to work on only one segment, as per your inputs.
The difference is that a segmented sieve proceeds by segments indefinitely and uses as many of the primes as needed by the segment currently being sieved (up to its top limit's square root); here the top segment's limit (and hence the core segment's) is known upfront.
The core segment extends up to the sqrt of the biggest value to be considered; here it is given to you as 10^9. sqrt(10^9) < 32000, so the core segment spans 0 to 32000, and is sieved by the simple sieve of Eratosthenes.
Since you have several runs, use the same core for each run.
The code in the linked answer is easily amended to this question's requirements: instead of estimating the top value, just use the n supplied to you in the input. above is what's called m here.

Calculating primes using only odd divisors is slower

I've written a small C program to calculate primes and now try to optimize the code as far as I can.
In the first revision of the program I was checking if a number was even (modulo 2) and if it was I would continue to the next number.
In my second revision I tried only checking odd numbers to be possible primes by incrementing the number I would be checking by 2 (so I would start from 3, then check 5, then 7, then 9, then 11 etc etc).
I thought this would be way faster as I had cut an extra check for modulo 2 with my code and simply replaced it with an addition.
However, to my surprise the code checking only odd numbers, runs a tad bit slower most of the times then the implementation checking all numbers.
Here is the code(it contains the changes I made between revisions in comments wherever it says //CHANGE)
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
unsigned long i = 3; //CHANGE No 1 - it was i = 2;
bool hasDivisor(unsigned long number)
{
//https://stackoverflow.com/questions/5811151/why-do-we-check-up-to-the-square-root-of-a-prime-number-to-determine-if-it-is-pr
unsigned long squareRoot = floor(sqrt(number));
//we don't check for even divisors - we want to check only odd divisors
//CHANGE No 2 - it was (number%2 ==0)
if(!((squareRoot&1)==0)) //thought this would boost the speed
{
squareRoot += 1;
}
for(unsigned long j=3; j <= squareRoot; j+=2)
{
//printf("checking number %ld with %ld \n", number, j);
if(number%j==0)
{
return true;
}
}
return false;
}
int main(int argc, char** argv)
{
printf("Number 2 is a prime!\n");
printf("Number 3 is a prime!\n");
while(true)
{
//even numbers can't be primes as they are a multiple of 2
//so we start with 3 which is odd and contiously add 2
//that we always check an odd number for primality
i++; //thought this would boost the speed instead of i +=2;
i++; //CHANGE No 3 - it was a simple i++ so eg 3 would become 4 and we needed an extra if(i%2==0) here
//search all odd numbers between 3 and the (odd ceiling) sqrt of our number
//if there is perfect division somewhere it's not a prime
if(hasDivisor(i))
{
continue;
}
printf("Number %ld is a prime!\n", i);
}
return 0;
}
I'm using Arch Linux x64 with GCC version 8.2.1 and compiling with:
gcc main.c -lm -O3 -o primesearcher
Although I tested with O1 and O2, as well.
I'm "benchmarking" with the command below:
./primesearcher & sleep 10; kill $!
which runs the program for 10seconds and outputs primes to the terminal for that time and then kills it.
I obviously tried allowing the program to run more (30, 60 and 180 seconds) but the results are about 9/10 of the time in favor of the version checking even numbers (modulo 2 version has found a bigger prime before it got killed).
Any idea why would this be happening?
Maybe something wrong in terms of code in the end?
Code is slower if(!((squareRoot&1)==0)) than with no test because it rarely has benefit.
Keep in mind that for most number, the iteration limit is never reached due to an early return from the number%j test. Primes tend to become rare as number grows.
An rare extra iteration is not offset by the repetitive cost of the test.
Comparing !((squareRoot&1)==0) to number%2 ==0 is moot.
OP's method of testing speed is error prone when differences are small: "runs a tad bit slower most of the times" shows the inconsistency.
A huge amount of time is in the printf(). To compare prime computation performance, I/O needs to be eliminated.
The kill is not that precise either.
Instead, form a loop to stop when i reaches a value like 4,000,000,000 and time that.
Code has other weaknesses:
unsigned long squareRoot = floor(sqrt(number)); can creates the wrong root for large number due to rounding when converting number to double and imprecision of the sqrt() routine. OP's reference addresses the mathematical algorithm need. Yet this C code implementation can readily fail given the limitations of real computations.
Instead, suggest
// Prime test for all unsigned long number
bool isPrime(unsigned long number) {
if (number % 2 == 0) { // This can be eliminated if `number` is always odd.
return number == 2;
}
for (unsigned long j = 3; j <= number/j; j += 2) {
if (number%j == 0) {
return false;
}
}
return number > 2;
}
The cost of number/j is often nil with modern compilers as they see number%j and effectively compute both quotient and remainder at once. Thus the limit of j <= squareRoot is achieved 1) without expensive sqrt() calculation 2) is accurate for large number, unlike sqrt() usage.
Use matching specifiers. u, not d for unsigned types.
// printf("Number %ld is a prime!\n", i);
printf("Number %lu is a prime!\n", i);
Use of a global i here is a weak coding style. Suggest re-coding and pass by function instead.
For more substantial improvements, look to Sieve of Eratosthenes and keeping a list of formerly found primes and test those rather than all odd numbers.
Prime testing is a deep subject with many more advanced ideas.

C prime factorization (loop failure?)

I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)
Could anyone of you with a fresh mind and view give me a little hint, where I might have the mistake in? (I am relatively new to C)
The problem is: The code works fine for most of the numbers I entered and tested, but accidentically I found a number that does not work: 3486118 (or 55777888 which is a multiple of it) It goes right for the first loop(s), but after factor 2 it becomes an endless loop.
Here is my code: (any help is greatly appreciated)
// Program calculates prime factors of entered number and returns them
#include <stdio.h>
int main() {
long int num, num_cp;
long int product=1;
/*prime number array up to 100.000*/
long int prime[] = {2, 3, **[...cut out MANY numbers...]** 99971, 99989, 99991};
printf("Please enter a positive integer:\n");
scanf("%li", &num);//55777888 or 3486118 not working... why?
//copy the entered number to keep the original for comparison with "product" and "break;" if equal
num_cp=num;
printf("prime factorization of %li:\n\n", num);
for (int i=0; i<sizeof(prime); i++) {
if (num_cp%prime[i]==0) {
num_cp/=prime[i];
product*=prime[i];
if (product==num) {
printf("%li\n\n", prime[i]);
break;
}
printf("%li*", prime[i]);
//If prime factor found but "product" is still not equal to "num" reset loop counter "i" to -1 (==0 in next loop)
i=-1;
}
}
printf("END");
return 0;
}
"I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)"
Don't. Leave it. Go away and eat a pizza. Veg out in front of your favourite movie. Have a shower. Aim for a new high-score on 2048 (or whatever). Your brain gets stuck in a rut and you are no longer seeing your code. You are only seeing what you think your code is.
When you get your brain out of the rut, then -- and only then -- go back and actually read the code you wrote. Not the code you think you wrote, but the code you actually wrote. Yes, they are different.
The prime factors of 55777888 are 2·2·2·2·2·1743059, where the last factor is too large to be contained in your list.
You can fix this in your code: When the product is equal to the product of the prime factors you have found, num_cp is 1. If num_cp is greater than one after you have exhausted your prime list, it is a factor of num. If num/num_cp is smaller than the largest prime you have checked, you can assume that the remaining value of num_cp is a prime. If it wasn't you'd have found more factors earlier.
You can fix this by adding an additional check after your main loop:
if (num_cp > 1) printf("%li\n\n", num_cp);
(If long int is a 64-bit number on your system, you're still not safe: The remaining factor might be made up of several numbers that are not in your array.)
Finally: Resetting the for loop counter so that the loop starts over isn't a good idea. It always starts from the beginning and re-checks primes that you have already checked. And it just isn't natural program flow, which makes it hard to read. A while loop instead of the inner if block would be more natural in my opinion.
Edit: To illustrate:
#include <stdio.h>
int main() {
long int num;
/* prime number array up to 100.000 */
long int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
int nprime = sizeof(prime) / sizeof(*prime);
num = 55;
printf("%li == ", num);
for (int i = 0; i < nprime; i++) {
long int p = prime[i];
if (num <= 1) break;
while (num % p == 0) {
num /= prime[i];
printf("%li", p);
if (num > 1) printf(" * ");
}
}
if (num > 1) printf("%li", num);
printf("\n");
return 0;
}
Things to note:
Instead of resetting the main loop counter i, a while loop is used, which consumes all repetitions of the same factor. If a prime p doesn't divide the number, the while loop isn't entered, just like an if clause.
I've removed the copy of num and used num throughout, mainly to remove clutter. I've also removed the product. Your logic that all prime factors should multiply to the original number, is good. But it also works the other way round: After dividing the number by all primes, we are left with 1. And we have to divide the number anyways. By removing the product, we have to keep track of only one variable instead of two.
I've moved the break condition to the front, so we catch negative numbers and 0 early.
That said, your way to code isn't wrong, just maybe a bit unusual in places.

C Program Runs Surprisingly Slow

A simple program I wrote in C takes upwards of half an hour to run. I am surprised that C would take so long to run, because from what I can find on the internet C ( aside from C++ or Java ) is one of the faster languages.
// this is a program to find the first triangular number that is divisible by 500 factors
int main()
{
int a; // for triangular num loop
int b = 1; // limit for triangular num (1+2+3+......+b)
int c; // factor counter
int d; // divisor
int e = 1; // ends loop
long long int t = 0; // triangular number in use
while( e != 0 )
{
c = 0;
// create triangular number t
t = t + b;
b++;
// printf("%lld\n", t); // in case you want to see where it's at
// counts factors
for( d = 1 ; d != t ; d++ )
{
if( t % d == 0 )
{
c++;
}
}
// test to see if condition is met
if( c > 500 )
{
break;
}
}
printf("%lld is the first triangular number with more than 500 factors\n", t);
getchar();
return 0;
}
Granted the program runs through a lot of data, but none of it is ever saved, just tested and passed over.
I am using the Tiny C Compiler on Windows 8.
Is there a reason this runs so slowly? What would be a faster way of achieving the same result?
Thank you!
You're iterating over a ton of numbers you don't need to. By definition, a positive factor is any whole number that can be multiplied by another to obtain the desired product.
Ex: 12 = 1*12, 2*6, and 3*4
The order of multiplication are NOT considered when deciding factors. In other words,
Ex: 12 = 2*6 = 6*2
The order doesn't matter. 2 and 6 are factors once.
The square root is the one singleton that will come out of a factoring of a product that stands alone. All others are in pairs, and I hope that is clear. Given that, you can significantly speed up your code by doing the following:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// this is a program to find the first triangular number that is divisible by 500 factors
int main()
{
int c = 0; // factor counter
long long int b = 0; // limit for triangular num (1+2+3+......+b)
long long int d; // divisor
long long int t = 0; // triangular number in use
long long int r = 0; // root of current test number
while (c <= 500)
{
c = 0;
// next triangular number
t += ++b;
// get closest root.
r = floor(sqrt(t));
// counts factors
for( d = 1 ; d < r; ++d )
{
if( t % d == 0 )
c += 2; // add the factor *pair* (there are two)
}
if (t % r == 0) // add the square root if it is applicable.
++c;
}
printf("%lld is the first triangular number with more than 500 factors\n", t);
return 0;
}
Running this on IDEOne.com takes less than two seconds to come up with the following:
Output
76576500 is the first triangular number with more than 500 factors
I hope this helps. (and I think that is the correct answer). There are certainly more efficient ways of doing this (see here for some spoilers if you're interested), but going with your code idea and seeing how far we could take it was the goal of this answer.
Finally, this finds the first number with MORE than 500 factors (i.e. 501 or more) as per your output message. Your comment at the top of the file indicates you're looking for the first number with 500-or-more, which does not match up with your output message.
Without any math analysis:
...
do
{
c = 0;
t += b;
b++;
for (d = 1; d < t; ++d)
{
if (!(t % d))
{
c++;
}
}
} while (c <= 500);
...
You are implementing an O(n^2) algorithm. It would be surprising if the code took less than a half an hour.
Refer to your computer science textbook for a better method compared to this brute force method of: check 1, 1 + 2, 1 + 2 + 3, etc.
You might be able to shorten the inner for loop. Does it really need to check all the way up to t for factors that divide the triangular number. For example, can 10 be evenly divisible by any number greater than 5? or 100 by any number greater than 50?
Thus, given a number N, what is the largest number that can evenly divide N?
Keep reading/researching this problem.
Also, as other people have mentioned, the outer loop could be simply coded as:
while (1)
{
// etc.
}
So, no need need to declare e, or a? Note, this doesn't affect the length of time, but your coding style indicates you are still learning and thus a reviewer would question everything your code does!!
You are doing some unnecessary operations, and I think those instructions are not at all required if we can check that simply.
first :
while(e!=0)
as you declared e=1, if you put only 1 in loop it will work. You are not updating value of e anywhere.
Change that and check whether it works fine or not.
One of the beautiful things about triangle numbers, is that if you have a triangle number, with a simple addition operation, you can have the next one.

Resources