I am starting to teach myself C and am trying to build a group of useful functions and programs for future reference. If relevant, this is C99.
Here is my most recent iteration of the program. At the output, I want to get the prime factorization of a number n. As is, however, I get a list of all factors, and no factors are repeated. I included some print statements to try and debug, and have found that the error is with the recursion, but can't figure out how to interpret it further. I previously tried making the recursive function of type int, but had difficulties getting it to work with the array p.
n is the number that I am trying to factor
p is an array for storing the found primes
j is an index for p
c is the number that I am testing as a divisor to n
I am aware that there are probably more efficient ways to declare p to save memory, but since this is mainly for reference, memory is not a huge concern.
I found these questions but don't think that they answer my question
finding greatest prime factor using recursion in c :This question is about crashing code. Mine compiles, runs, and produces reasonably sensible output, I'm just wondering why the output isn't what I expect.
is there ever a time you would not use recursion? [closed] :This indicates that recursion is not a good choice for prime factorization- I don't know, but suspect that this would also apply to C. Since this is for reference, I don't think it is a huge issue. If you disagree, please explain why.
My main questions are these:
Why does the output show all factors of n?
Why does it not repeat the prime factors?
What do I have to do to fix it?
#include <stdio.h>
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
void factors(int n, int p[], int j) {
/// if n is divisible by c, store c, and continue with n/c
int c;
for (c=2; c < n; c++) {
if (c > n) break;
if (n%c == 0) {
p[j] = c;
printf("%d has been added to p \t", c);
printf("n has been reduced to %d \t", n/c);
printf("j is %d \n", j);
j++;
if (n == c) break;
factors(n/c, p, j);
}
}
}
int main() {
/// set up number to factor, and array to hold factors
int n = 24;
int p[n/2];
int i=0;
for (i=0; i<NELEMS(p); i++) {
p[i]=0;
}
int j = 0;
factors(n, p, j);
printf("the prime factors of %d are:\n",n);
for (i=0; i<NELEMS(p); i++) {
printf("%d \n", p[i]);
}
}
You have already been told in comments that this algorythm is poor, which is an evidence here. And you really should learn to use a debugger: running this through a debugger immediately shows where the problems are.
That being said, your main problem here is what to do when the recursive functions return?. You failed to ask yourself this question which is a must in recursion, and simply continue in sequence, which is plain wrong because you will reuse a number that has already been processed in the recursive calls. So you must add a return line immediately after recursively calling factors.
Once this is done, there is another minor problem (that a debugger would make evident), you only search factors strictly lesser that n. So you miss the last prime factor...
With those 2 immediate fixes, your code becomes:
void factors(int n, int p[], int j) {
/// if n is divisible by c, store c, and continue with n/c
int c;
for (c=2; c <= n; c++) {
if (c > n) break;
if (n%c == 0) {
p[j] = c;
printf("%d has been added to p \t", c);
printf("n has been reduced to %d \t", n/c);
printf("j is %d \n", j);
j++;
if (n == c) break;
factors(n/c, p, j);
return;
}
}
}
But IMHO p[j] = c; should become *p = c; and factors(n/c, p, j); should become factors(n/c, p+1, j);. Said differently you pass directly a pointer to the next slot.
Edit It occurs to me that the smallest factor of n is guaranteed to be prime, so I have edited the answer accordingly.
Why does the output show all factors of n?
Because you test if c is a factor of n and add it to the array p whether c is prime or not. Then you carry on testing numbers above c, even multiples of c.
Why does it not repeat the prime factors?
Because when you find a number c that is a factor, you don't necessarily inspect it to find out if it is a compound number itself.
After adding c to p, you need to recursively call factor on (n / c) and then stop.
Here is roughly what you need (but not tested or even compiled)
int factorise(int n, int p[], int j)
{
int factorsFound = 0;
for (c = 2 ; c * c <= n && factorsFound == 0 ; ++ c)
{
if (n % c == 0)
{
p[j] = c;
factorsFound = factorise(n / c, p, j + 1) + 1;
}
}
if (factorsFound == 0) // n is prime
{
p[j] = n;
factorsFound = 1;
}
return factorsFound;
}
Also in a real solution, you probably want to pass the size of p so that you can detect if you run out of space.
Just for fun, since nobody else has posted it yet, here is a non recursive solution. It's actually the same as above but the recursion has been transformed into a loop.
int factorise(int number, int p[])
{
int j = 0;
for (int c = 2, int n = number ; n > 1 ; )
{
if (n % c = 0)
{
p[j++] = c;
n = n / c;
}
else
{
c++;
}
}
return j;
}
I disagree with some of Lundin's comments about recursion. Recursion is a natural way of breaking a problem down into easier subtasks but in C it is undeniably less efficient, especially in terms of stack space and in this particular case, the non recursive version is simpler.
From This answer:
why does recursion cause stackoverflow so much more than loops do
Because each recursive call uses some space on the stack. If your recursion is too deep, then it will result in StackOverflow, depending upon the maximum allowed depth in the stack.
When using recursion, you should be very careful and make sure that you provide a base case. A base case in recursion is the condition based on which the recursion ends, and the stack starts to unwind. This is the major reason of recursion causing StackOverflow error. If it doesn't find any base case, it will go into an infinite recursion, which will certainly result in error, as Stack is finite only.
-
It appears that your for is in the way, c will increment, and wont check that same value again.
For instance, if the input is 8, we want (2,2,2) and not (2,4).
I would recommend replacing your if (c%n ==0) by a while, don't forget to replace the value of n in that while, you don't want to loop in that.
This appears to be a good answer :
int primes(int nbr, int cur)
{
if (cur > nbr)
return (0);
else
{
if (nbr % cur == 0 && isprime(cur) == 1)
{
printf("%d\n", cur);
return (primes(nbr / cur, 2));
}
return (primes(nbr, cur + 1));
}
}
Call that function with cur = 2 in your main
Related
I have to print numbers between two limits n and m, t times.
I created t variable, and two pointers n, m that points to reserved blocks of memory for t integer values.
I use pointers instead of array to do faster operations.
Outer for loop iterates for every test cases and increasing m and n pointers.
Inner for loop prints primes from m[i] to n[i].
Code
#include <stdio.h>
#include <stdlib.h>
int is_prime(int);
int main(void) {
int t;
int *n = malloc(sizeof(int) * t);
int *m = malloc(sizeof(int) * t);
scanf("%d", &t);
for (int i = 0; i < t; i++, m++, n++) {
scanf("%d %d", &m[i], &n[i]);
for (int j = m[i]; j <= n[i]; j++) {
if (is_prime(j)) {
printf("%d\n", j);
}
}
if (i < t - 1) printf("\n");
}
return 0;
}
int is_prime(int num)
{
if (num <= 1) return 0;
if (num % 2 == 0 && num > 2) return 0;
for(int i = 3; i < num / 2; i+= 2){
if (num % i == 0)
return 0;
}
return 1;
}
Problem: http://www.spoj.com/problems/PRIME1/
Code is correctly compiling on http://ideone.com but I'm giving "time limit exceeded" error when I'm trying submit this code on SPOJ. How can I reduce execution time of this prime number generator?
As #Carcigenicate suggests, you're exceeding the time limit because your prime generator is too slow; and it's too slow since you're using an inefficient algorithm.
Indeed, you should not simply test each consecutive number for primality (which, by the way, you're also doing ineffectively), but rather rule out multiple values at once using known primes (and perhaps additional primes which you compute). For example, you don't need to check multiples of 5 and 10 (other than the actual value 5) for primality, since you know that 5 divides them. So just "mark" the multiples of various primes as irrelevant.
... and of course, that's just for getting you started, there are all sort of tricks you could use for optimization - algorithmic and implementation-related.
I know that you are looking for algorithm improvements, but the following technical optimizations might help:
If you are using Visual Studio, you can use alloca instead of malloc, so that n and m go in the stack instead of the heap.
You can also try to rewrite your algorithm using arrays instead of pointers to put n and m in the stack.
If you want to keep using pointers, use the __restrict keyword after the asterisks, which alerts the compiler that you don't make references of the two pointers.
You can even do it without using pointers or arrays
#include <stdio.h>
#include<math.h>
int is_prime(long n){
if (n == 1 || n % 2 == 0)
return 0;
if (n == 2)
return 1;
for (long i = 3; i <= sqrt(n); i += 2) {
if(n % i == 0)
return 0;
}
return 1;
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
long n, m;
scanf("%ld %ld",&n,&m);
for (long i = n; i <= m; i++) {
if (is_prime(i) == 1)
printf("%ld\n",i);
}
}
return 0;
}
There are several ways to improve the primality check for an integer n. Here are a few that you might find useful.
Reduce the number of checks: A well known theorem is giving the fact that if you want to look for factors of n, let say n = a * b, then you can look for a divisor between 1 and sqrt(n). (Proof is quite easy, the main argument being that we have three cases, either a = b = sqrt(n), or we have a < sqrt(n) < b or b < sqrt(n) < a. And, whatever case we fall in, there will be a factor of n between 1 and sqrt(n)).
Use a Sieve of Eratosthenes: This way allows to discard unnecessary candidates which are previously disqualified (see Sieve of Eratosthenes (Wikipedia))
Use probabilistic algorithms: The most efficient way to check for primality nowadays is to use a probabilistic test. It is a bit more complex to implements but it is way more efficient. You can find a few of these techniques here (Wikipedia).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
So I am running into an issue that I can't seem to fix. I want to display the factor and the power that it is raised to(basically prime factor decomposition), I had done this in python but for some reason I can't implement this in C and this is what I came up with
#include<stdio.h>
#include<math.h>
int main()
{
int i = 2, p, c, n;
scanf("%d", n);
while (n > 9)
{
p = 0;
c = 1;
while (n % i == 0)
{
for (int d = 2; d <= i / 2 + 1; d++)
if (i % d == 0 && i % 2 != 0)
c = 0;
if (c == 1)
{
p = p + 1;
n = n / i;
}
if (p != 0)
{
printf("%d %d", i, p);
printf("\n");
}
i = i + 1;
}
}
return 0;
}
Problem #1 (although it's not your main problem) is that you're missing a pointer in your scanf call:
scanf("%d", n);
That needs to be
scanf("%d", &n);
(My compiler warned me about this right away. Not sure why yours didn't.)
Problem #2 is that while (n > 9) is just totally wrong. I think you want while (n > 1).
Problem #3 is that the i = i + 1 step is misplaced. You need to do that whether or not i was a factor, so it needs to be at the end of the outermost loop.
And then problem #4 is the code that starts with
for (int d = 2; d <= i / 2 + 1; d++)
It looks like you're trying to check whether i is prime, although you're doing it too late: you're already inside the if where you test whether i is a factor of n. Also you don't have a proper loop to count how many times i is a factor of n.
It turns out, though, that you don't actually need to test whether i is prime, so let's leave the primality-testing step out for a moment and see what happens.
Here's the first fixed version:
#include <stdio.h>
int main()
{
int i = 2, p, n;
scanf("%d", &n);
while (n > 1)
{
if (n % i == 0) /* if i is a factor */
{
p = 0;
while (n % i == 0) /* count how many times i is a factor */
{
n /= i;
p++;
}
printf("%d %d\n", i, p);
}
i++;
}
return 0;
}
And this works! It tries every possible value of i, which is pretty inefficient, but due to the properties of prime factorization, it's okay. It tries them in order, so it will always have weeded out all lower prime factors first, so none of the non-prime i's will make it through to get printed as a factor.
To do what I guess you were trying to do, we have to rearrange the code. The basic algorithm is: for each i, if it's prime, see how many times it divides the running n.
#include <stdio.h>
int main()
{
int i = 2, p, c, n;
scanf("%d", &n);
while (n > 1)
{
/* see if i is prime */
c = 1;
for (int d = 2; d <= i / 2 + 1; d++)
if (i % d == 0 && i % 2 != 0)
{
c = 0;
break;
}
if (c == 1) /* if i is prime */
{
p = 0;
while (n % i == 0) /* count how many times i is a factor */
{
p = p + 1;
n = n / i;
}
if (p != 0)
printf("%d %d\n", i, p);
}
i = i + 1;
}
return 0;
}
The primality test is still pretty crude (that line if (i % d == 0 && i % 2 != 0) is fishy), but it seems to work. I suspect it's still wasteful, though: if you're generating all possible trial divisors to factorize n, there's probably a better way than running a full primality test on each i, from scratch.
One popular shortcut is to have i run through 2,3,5,7,9,11,13,... (that is, 2 plus all the odd numbers). Building on that idea, I once wrote some code that uses a more complicated sequence of increments so that it ends up using 2, 3, 5, and then every odd number that isn't a multiple of 3 or 5. I suspect (but I haven't measured) that wastefully using some number of non-prime trial divisors i might end up being less wasteful than positively confirming that each trial divisor is strictly prime.
But if you really care about efficiency, you'll have to abandon this obvious but still rather brute-force technique of blindly trying all the trial divisors, and move to something more sophisticated like elliptic curve factorization. What we're doing here is trial division, which as Wikipedia notes is "the most laborious but easiest to understand of the integer factorization algorithms".
I have to print numbers between two limits n and m, t times.
I created t variable, and two pointers n, m that points to reserved blocks of memory for t integer values.
I use pointers instead of array to do faster operations.
Outer for loop iterates for every test cases and increasing m and n pointers.
Inner for loop prints primes from m[i] to n[i].
Code
#include <stdio.h>
#include <stdlib.h>
int is_prime(int);
int main(void) {
int t;
int *n = malloc(sizeof(int) * t);
int *m = malloc(sizeof(int) * t);
scanf("%d", &t);
for (int i = 0; i < t; i++, m++, n++) {
scanf("%d %d", &m[i], &n[i]);
for (int j = m[i]; j <= n[i]; j++) {
if (is_prime(j)) {
printf("%d\n", j);
}
}
if (i < t - 1) printf("\n");
}
return 0;
}
int is_prime(int num)
{
if (num <= 1) return 0;
if (num % 2 == 0 && num > 2) return 0;
for(int i = 3; i < num / 2; i+= 2){
if (num % i == 0)
return 0;
}
return 1;
}
Problem: http://www.spoj.com/problems/PRIME1/
Code is correctly compiling on http://ideone.com but I'm giving "time limit exceeded" error when I'm trying submit this code on SPOJ. How can I reduce execution time of this prime number generator?
As #Carcigenicate suggests, you're exceeding the time limit because your prime generator is too slow; and it's too slow since you're using an inefficient algorithm.
Indeed, you should not simply test each consecutive number for primality (which, by the way, you're also doing ineffectively), but rather rule out multiple values at once using known primes (and perhaps additional primes which you compute). For example, you don't need to check multiples of 5 and 10 (other than the actual value 5) for primality, since you know that 5 divides them. So just "mark" the multiples of various primes as irrelevant.
... and of course, that's just for getting you started, there are all sort of tricks you could use for optimization - algorithmic and implementation-related.
I know that you are looking for algorithm improvements, but the following technical optimizations might help:
If you are using Visual Studio, you can use alloca instead of malloc, so that n and m go in the stack instead of the heap.
You can also try to rewrite your algorithm using arrays instead of pointers to put n and m in the stack.
If you want to keep using pointers, use the __restrict keyword after the asterisks, which alerts the compiler that you don't make references of the two pointers.
You can even do it without using pointers or arrays
#include <stdio.h>
#include<math.h>
int is_prime(long n){
if (n == 1 || n % 2 == 0)
return 0;
if (n == 2)
return 1;
for (long i = 3; i <= sqrt(n); i += 2) {
if(n % i == 0)
return 0;
}
return 1;
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
long n, m;
scanf("%ld %ld",&n,&m);
for (long i = n; i <= m; i++) {
if (is_prime(i) == 1)
printf("%ld\n",i);
}
}
return 0;
}
There are several ways to improve the primality check for an integer n. Here are a few that you might find useful.
Reduce the number of checks: A well known theorem is giving the fact that if you want to look for factors of n, let say n = a * b, then you can look for a divisor between 1 and sqrt(n). (Proof is quite easy, the main argument being that we have three cases, either a = b = sqrt(n), or we have a < sqrt(n) < b or b < sqrt(n) < a. And, whatever case we fall in, there will be a factor of n between 1 and sqrt(n)).
Use a Sieve of Eratosthenes: This way allows to discard unnecessary candidates which are previously disqualified (see Sieve of Eratosthenes (Wikipedia))
Use probabilistic algorithms: The most efficient way to check for primality nowadays is to use a probabilistic test. It is a bit more complex to implements but it is way more efficient. You can find a few of these techniques here (Wikipedia).
Well, there are lots of such questions available in SO as well as other forums. However, none of these helped.
I wrote a program in "C" to find number of primes within a range. The range i in long int. I am using Sieve of Eratosthenes" algorithm. I am using an array of long ints to store all the numbers from 1 till the limit. I could not think of a better approach to achieve without using an array. The code works fine, till 10000000. But after that, it runs out of memory and exits. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef unsigned long uint_32;
int main() {
uint_32 i, N, *list, cross=0, j=4, k, primes_cnt = 0;
clock_t start, end;
double exec_time;
system("cls");
printf("Enter N\n");
scanf("%lu", &N);
list = (uint_32 *) malloc( (N+1) * sizeof(uint_32));
start = clock();
for(i=0; i<=N+1; i++) {
list[i] = i;
}
for(i=0; cross<=N/2; i++) {
if(i == 0)
cross = 2;
else if(i == 1)
cross = 3;
else {
for(j=cross+1; j<=N; j++) {
if(list[j] != 0){
cross = list[j];
break;
}
}
}
for(k=cross*2; k<=N; k+=cross) {
if(k <= N)
list[k] = 0;
}
}
for(i=2; i<=N; i++) {
if(list[i] == 0)
continue;
else
primes_cnt++;
}
printf("%lu", primes_cnt);
end = clock();
exec_time = (double) (end-start);
printf("\n%f", exec_time);
return 0;
}
I am stuck and can't think of a better way to achieve this. Any help will be hugely appreciated. Thanks.
Edit:
My aim is to generate and print all prime numbers below the range. As printing consumed a lot of time, I thought of getting the first step right.
There are other algorithm that does not require you to generate prime number up to N to count number of prime below N. The easiest algorithm to implement is Legendre Prime Counting. The algorithm requires you to generate only sqrt(N) prime to determine the number of prime below N.
The idea behind the algorithm is that
pi(n) = phi(n, sqrt(n)) + pi(sqrt(n)) - 1
where
pi(n) = number of prime below N
phi(n, m) = number of number below N that is not divisible by any prime below m.
That's mean phi(n, sqrt(n)) = number of prime between sqrt(n) to n. For how to calculate the phi, you can go to the following link (Feasible implementation of a Prime Counting Function)
The reason why it is more efficient is because it is easiest to compute phi(n, m) than to compute pi(n). Let say that I want to compute phi(100, 3) means that how many number below or equal to 100 that does not divisible by 2 and 3. You can do as following. phi(100, 3) = 100 - 100/2 - 100/3 + 100/6.
Your code uses about 32 times as much memory as it needs. Note that since you initialized list[i] = i the assignment cross = list[j] can be replaced with cross = j, making it possible to replace list with a bit vector.
However, this is not enough to bring the range to 264, because your implementation would require 261 bytes (2 exbibytes) of memory, so you need to optimize some more.
The next thing to notice is that you do not need to go up to N/2 when "crossing" the numbers: √N is sufficient (you should be able to prove this by thinking about the result of dividing a composite number by its divisors above √N). This brings memory requirements within your reach, because your "crossing" primes would fit in about 4 GB of memory.
Once you have an array of crossing primes, you can build a partial sieve for any range without keeping in memory all ranges that precede it. This is called the Segmented sieve. You can find details on it, along with a simple implementation, on the page of primesieve generator. Another advantage of this approach is that you can parallelize it, bringing the time down even further.
You can tweak the algorithm a bit to calculate the prime numbers in chunks.
Load a part of the array (as much as fits the memory), and in addition hold a list of all known prime numbers.
Whenever you load a chunk, first go through the already known prime numbers, and similar to the regular sieve, set all non primes as such.
Then, go over the array again, mark whatever you can, and add to the list the new prime numbers found.
When done, you'll have a list containing all your prime numbers.
I could see that the approach you are using is the basic implementation of Eratosthenes, that first stick out all the 2's multiple and then 3's multiple and so on.
But I have a better solution to the question. Actually, there is question on spoj PRINT. Please go through it and do check the constraints it follows. Below is my code snippet for this problem:
#include<stdio.h>
#include<math.h>
#include<cstdlib>
int num[46500] = {0},prime[5000],prime_index = -1;
int main() {
/* First, calculate the prime up-to the sqrt(N) (preferably greater than, but near to
sqrt(N) */
prime[++prime_index] = 2; int i,j,k;
for(i=3; i<216; i += 2) {
if(num[i] == 0) {
prime[++prime_index] = i;
for(j = i*i, k = 2*i; j<=46500; j += k) {
num[j] = 1;
}
}
}
for(; i<=46500; i+= 2) {
if(num[i] == 0) {
prime[++prime_index] = i;
}
}
int t; // Stands for number of test cases
scanf("%i",&t);
while(t--) {
bool arr[1000005] = {0}; int m,n,j,k;
scanf("%i%i",&m,&n);
if(m == 1)
m++;
if(m == 2 && m <= n) {
printf("2\n");
}
int sqt = sqrt(n) + 1;
for(i=0; i<=prime_index; i++) {
if(prime[i] > sqt) {
sqt = i;
break;
}
}
for(; m<=n && m <= prime[prime_index]; m++) {
if(m&1 && num[m] == 0) {
printf("%i\n",m);
}
}
if(m%2 == 0) {
m++;
}
for(i=1; i<=sqt; i++) {
j = (m%prime[i]) ? (m + prime[i] - m%prime[i]) : (m);
for(k=j; k<=n; k += prime[i]) {
arr[k-m] = 1;
}
}
for(i=0; i<=n-m; i += 2) {
if(!arr[i]) {
printf("%i\n",m+i);
}
}
printf("\n");
}
return 0;
}
I hope you got the point:
And, as you mentioned that your program is working fine up-to 10^7 but above it fails, it must be because you must be running out of the memory.
NOTE: I'm sharing my code only for knowledge purpose. Please, don't copy and paste it, until you get the point.
This is probably a really simple problem to solve but for for some reason I just can't think of the correct solution!
We have a function int isPrime(int n) which returns a 2 if n is prime, a -1 if n is not positive and a 0 if n isn't prime. (We don't have to write any code for this function, we just assume that the code is already written so all we have to do is call this function). Using this function, we have to write a code fragment that fills up an integer array of size 10 with the first ten prime numbers. NOTE: Treat 1 as a non-prime number.
I've attempted a solution below but I don't think it's right:
NOTE: We just have to write a code fragment!
int a[10];
int n, i, result;
result = isPrime(n);
for (i = 0; i < 10; i++) {
if (result == 1) {
a[i] = n;
}
}
I have a feeling that I will have to use two for loops, one to cycle through the numbers being checked with isPrime and another one to loop through the positions in the array as I have above. But I'm not sure how it would look if I had two for loops. Any help is appreciated! Thanks ahead of time.
Try something like this. It will repeatedly find the next prime until you have found 10 of them.
Note: Since you did not provide an implementation of isPrime, this code is not tested. It is only meant to give you an idea of what it should look like.
int a[10];
int n, i, result;
n = 2;
for (i = 0; i < 10; i++) {
// Keep bumping n until we find a prime.
while (!(isPrime(n) == 2)) {
n++;
}
// Record the prime we just found.
a[i] = n;
// Ensure that we do not just record the same prime n times.
n++;
}
Start by having zero primes. While you don't have 10 of them, see if the next number is prime; if it is, add it to the next spot in the array if it is (and now you have one more prime).
(This straightforwardly translates into code. You need one loop, but two different counters: number of found primes, and number you're testing next)
An implementation of Amaden's algorithm:
int a[10];
for (int n = 1, nprimes = 0;;)
if (isPrime(++n) == 2) {
a[nprimes++] = n;
if (nprimes == 10)
break;
}