Finding proper divisors in c - c

I'm trying to write a function that finds the number of divisors of a number n, which are smaller or equal to a number k using recursion (in C programming language).
For example, (9,3) should return 2 since the only positive divisors of 9 that are less than or equal to 3 are 1 and 3.
Here's what I've tried but can't figure out why it's not working:
int divisors(int n,int k){
int sum = 0;
if (k==0){
return 0;
}
else if (n%k==0){
return sum++ + divisors(n,k-1);
}
return sum;
}
If anyone is able to help I'd appreciate it.

You are almost there. I made a few fixes:
k == 1 as a break condition is faster, although k == 0 works fine.
The integer sum is useless.
When not counting, your thinking was almost correct. You should return 0 but for this specific case while keeping the function calculating the next ints (recursion). Therefore you should return 0 + divisors(n, k-1)
int divisors(int n,int k){
if (k == 1) return 1;
if (n % k == 0) return 1 + divisors(n, k-1);
return divisors(n, k-1);
}

You are not handling the resolution of the recursion properly
There is no need for a sum variable, instead you want to return the function call (or 0) in any case.
If you find a number so that n%k==0 holds true, you want to return 1 + the results of the next case. However, if you then find a number that is neither 0, nor a match it will stop, instead of checking all numbers down to 0. Therefore adjusting your code in the following way will solve the problem:
int divisors(int n,int k){
if (k==0)
return 0;
else if (n%k==0)
return divisors(n,k-1) + 1;
else
return divisors(n,k-1);
}

Related

Factorial as a sum of consecutive number

I was recently solving a problem "No. of ways to express factorial of a number as sum of consecutive number"
My solution is :
int fact_as_sum(int n) { // n is the number whose factorial need to be taken
long int fact=1;
int temp=0,count=0;
for(int i=n;i>0;i--){
fact*=i;
}
printf("%d\n",fact);
for(int i=fact/2;i>0;i--) {
int j=i;
temp=fact;
while(temp>=0) {
if(temp==0) {
count++;
break;
}
else
temp-=j;
j--;
}
}
return count;
}
The solution works correct till small no. of 10!.
But my solution has high complexity.
Can anyone suggest a less complex solution ?
Thanks
Ok, so this problem tickled my brain a lot, so first of all thank you for that, I love to solve these kind of problems!
I started with a math analysis of the problem in order to find the best implementation, and I came up with this solution:
By defining n as the factorial result number, m the number of sums to be performed and x the starting number for the addition, it all breaks down to the following formula:
.
This can now be simplified, resulting in the following formula:
.
That can be also simplified, giving the following result:
.
Solving for x (the starting number for addition), results in:
.
It is now possible to iterate for all the values of m to find the wanted x value. the lower bound for m is for sure 0, it is not possible to add a negative quantity of numbers! The top bound can be found by noticing that x should be a positive number, it would have no sense to consider negative values that will be nulled by the corresponding positive part! This gives the following result:
That yields the following result:
The negative value of m is discarded as previously said.
This translates in the following C code:
#include <stdio.h>
#include <math.h>
void main() {
int fact = 8; //select the wanted factorial to compute
float n = 1;
int i;
float x;
float m;
printf("calculating %d factorial...\n", fact);
for (i = 2; i < fact + 1; i++) {
n *= (float)i;
}
printf("the factorial result is %d\n", (int)n);
printf("calculating the sum of consecutive numbers...\n");
//compute the maximum number of iterations
int maxIter = (int)((-1 + sqrt(1 + 8 * n)) / 2);
for (i = 0; i < maxIter; i++) {
m = (float)i;
//apply the formula
x = (n / (m + 1)) - (m / 2);
if (x - (float)((int)x) == 0) {
printf("found a correct sum!\n");
printf("the starting number is: %d\n", (int)x);
printf("the number of sums is: %d\n", i + 1);
}
}
}
I've tried this solution on a couple of values and wrote the code for the test, the results seem right. There is an issue with the factorial though, since the factorial reaches very high values quickly, memory needs to be managed better.
Hope I gave an interesting solution, I had fun solving it!
Please correct in case there are problems with this solution.
Sure. I may try and give a simpler solution for finding the count: replace
temp = fact;
while(temp>=0) {
if(temp==0) {
count++;
break;
}
else
temp-=j;
j--;
}
by
if ( fact % j == 0 )
count++;
. This also means you don't need temp, since you can use the remainder operator (%) to check for whether j is a divisor (that's what you tried to do in that while loop, right?).
Fist of all, your code has a bug.
1. You need to change i=fact/2 in for loop to i=(fact+1)/2;
2. You need to add j > 0 condition in while loop to prevent infinite loop. Because for example temp-(-1) will increment temp.
Fixed code:
for(long int i=(fact+1)/2; i>0; i--) {
long int j=i;
temp=fact;
while(j > 0 && temp > 0) {
temp-=j;
j--;
if(temp == 0) {
count++;
break;
}
}
}
As of your question, it can be done in O(sqrt(2*N)) time. Here are some understandable, clean answers:
long int count = 0;
for (long int L = 1; L * (L + 1) < 2 * fact; L++) {
float a = (1.0 * fact-(L * (L + 1)) / 2) / (L + 1);
if (a-(int)a == 0.0)
count++;
}
https://www.geeksforgeeks.org/count-ways-express-number-sum-consecutive-numbers/
https://math.stackexchange.com/questions/139842/in-how-many-ways-can-a-number-be-expressed-as-a-sum-of-consecutive-numbers

Factorization in C-Recursion

I've been asked to write a void function in c(no loops), that gets an even number(lets say 80), and prints it like this
2*2*5*2*2
As you can see the result is 80 lol.
Between 2 numbers you need to print "*", and the odd number(for my example,5) you need to print it in the middle, or if there is an odd numbers of "2" in the number, lets say 96 you need to print it like that:2*2*2*3*2*2
If the given number is odd, return the number.
I whould like to get not only te answer, but the way you "think" before starting to code.
Here is what i got so far
if(n%4==0)
{
printf("2*");
PrintTwos(n/4);
return;
}
if(n%2==0)
{
printf("*2");
PrintTwos(n/2);
return;
}
printf("%d",n);
here is some pseudo code:
func(nbr)
isOdd(nbr) // recursive stop condition
print nbr
return
evenNbr = findFirstEven(nbr) //return the shortest even number from nbr
print evenNbr
func(nbr / evenNbr)
I didn't add logic for the * printing because i'm sure u can figure that about by yourself. And one case will break that pseudo code, but that's a good start to help you thinking about what your recursive function should do.
EDIT following comments: (NOT COMPLETE : odd number in the middle is missing in this)
int findFirstEven(nbr, i) {
if (nbr%i != 0)
return findFirstEven(nbr, i++);
return i;
}
int primefact(int n)
{
int i=2;
i = findFirstEven(n, i);
printf("%d*", i);
if(n==i)
printf("1");
return 0;
else
primefact(n/i);
}
(not tested)
You need to distribute 2's in halves, so you need to remove two twos from the number before the recursive step – otherwise the recursive step would have to know how deep it is to keep from printing too many twos on the left side.
Of course you must verify if there actualy are two twos!
So:
void PrintTwosInNumber(unsigned n)
{
if(n % 4 == 0)
{
printf("2*");
PrintTwosInNumber(n/4);
printf("*2");
}
else if(n % 2 == 0)
{
printf("2*");
PrintTwosInNumber(n/2);
}
else
printf("%u", n);
}
You can save the last recursive step with
void PrintTwosInNumber(unsigned n)
{
if(n % 4 == 0)
{
printf("2*");
PrintTwosInNumber(n/4);
printf("*2");
}
else if(n % 2 == 0)
printf("2*%u", n/2);
else
printf("%u", n);
}
Edit:
Please note the function will fall into an infinite recursion for n==0 – zero is infinitely divisible by 2. However, zero can not be represented as a product of any number of 2's and some odd numer, so it is out of scope of this problem.
Anyway if it was a real programming task, one should take that special case into account and add a protecting if(n==0) return; branch, just to be on the safe side if a caller passes a wrong parameter value.

checking for co-prime in C prgramming language

#include <stdio.h>
int iscoprime(int num1, int num2);
int main() {
int x;
x = iscoprime( 7, 8 );
printf("%d",x);a
}
int iscoprime(int num1, int num2) {
int r = 0;
int gcd = 0;
int i;
for(i = 0; (i < num1) || (i < num2) ; ++i) {
if( (num1 % i == 0) && (num2 % i == 0)) {
gcd = i;
}
}
if ( gcd == 1 ) r = 1;
return r;
}
Error: this program has stopped..??? :(
Your program has some flaws.
1) The for loop starts with i value 0. So, in the first iteration itself, floating point exception will occur. It should start from 1.
2) Your question stated that the program is finding the gcd. Which doesn't seem to be the matter. It seems to me that it is finding whether the given numbers are co-prime or not.
If its a GCD program, the return statement should be
return gcd; //without the previous if condition
Its unclear what you want your return value to mean from the iscoprime function. It looks like it returns the greatest common divisor and then checks if it is 1, then the two inputs are co-prime, and else it uses r's initial value of 0 hence meaning it will print 1 if the numbers are co-prime and 0 if they are not. Your for loop doesn't quite make sense. The max greatest common divisor of two numbers can have would be the lower of the two values. I would start your for loop at this value, 7 in your case and decrement i with each iteration and return i when both numbers divide by i without a remainder. This would would then be your greatest common divisor, if it is 1, then your two numbers are co-prime.
While this implementation is fine for small numbers, if the numbers are going to be very large, I would have a look at https://en.wikipedia.org/wiki/Euclidean_algorithm which can compute the GCD very fast and the same will still apply, if the GCD is 1, the two inputs are co-prime.

Why does recursive function count downwards after peak?

with fear that I may overstep another question of mine (although this is a new problem alltogether) I still ask this question.
I have this code:
int blob_count(int y, int x, int gridCopy[][5], int sum){
//Local vars
int posX, posY;
//Find the position 1 behind and 1 above the starting point, and start the loop there
for(posX = -1;posX <=1; posX++){
for(posY = -1; posY <= 1; posY++){
if((y + posY) >= 0 && (x + posX) >= 0){
if((y + posY) <= 5 && (x + posX) <= 5){
if(gridCopy[posY+y][posX+x] == 1){
//Set the starting point to 0 (so it wont get calculated again)
gridCopy[posY+y][posX+x] = 0;
y = posY+y;
x = posX+x;
sum++;
blob_count(y, x, gridCopy, sum);
}
}
}
}
}
return sum;
}
The issue is that sum, which counts up 1, for each recursive run, returns the wrong value. By doing a print for each recursive run it gives the result:
sum = 1
sum = 2
sum = ...
sum = n
Which is great, however, by setting printing out the sum outside the for loop (right before return sum;) the opposite happens when it has peaked, so it does this:
sum = n
sum = ...
sum = 2
sum = 1
return sum; // = 1
Which is obviously wrong, as I want the total count, not the lowest. Have I got the return value the wrong place? I've tried putting it in right after the recursive call (inside the loop), to no avail.
Okay let's get rid of the extra bits and simplify your problem down to the essentials.
You have:
int blob_count(int sum)
{
sum++;
if (sum < 10)
blob_count(sum);
return sum;
}
If you add printf("sum==%d\n", sum) right before the return then it will be called first at the innermost recursion (where sum == 10), then it will return to the next level out where sum == 9, print that, return to sum == 8 and so on.
If you put it before the recursive call to blob_count(sum) then you'll print the values before you recurse down, so they start with sum==0, sum == 1 and so on.
If you want sumto be the deepest level your recursion got to, then you could either pass it back via the return value like this:
int blob_count(int sum)
{
sum++;
if (sum < 10)
sum = blob_count(sum);
return sum;
}
or you could pass it via a pointer so that the original variable gets modified:
void blob_count(int* sum)
{
*sum++;
if (*sum < 10)
blob_count(sum);
return;
}
The first one is probably the solution you are looking for.
What pmg said. For each recursive call, the current value of sum is copied and the copy is passed to the recursive call. If you want to modify objects in functions, you must pass a pointer to these objects instead of the object itself.

Are You A Prime Number

I've been interested in the problem of finding a better prime number recognizer for years. I realize this is a huge area of academic research and study - my interest in this is really just for fun. Here was my first attempt at a possible solution, in C (below).
My question is, can you suggest an improvement (without citing some other reference on the net, I'm looking for actual C code)? What I'm trying to get from this is a better understanding of determining performance complexity of a solution like this.
Am I right in concluding that the complexity of this solution is O(n^2)?
#include <stdio.h>
#include <math.h>
/* isprime */
/* Test if each number in the list from stdin is prime. */
/* Output will only print the prime numbers in the list. */
int main(int argc, char* argv[]) {
int returnValue = 0;
int i;
int ceiling;
int input = 0;
int factorFound = 0;
while (scanf("%d", &input) != EOF) {
ceiling = (int)sqrt(input);
if (input == 1) {
factorFound = 1;
}
for (i = 2; i <= ceiling; i++) {
if (input % i == 0) {
factorFound = 1;
}
}
if (factorFound == 0) {
printf("%d\n", input);
}
factorFound = 0;
}
return returnValue;
}
for (i = 2; i <= ceiling; i++) {
if (input % i == 0) {
factorFound = 1;
break;
}
}
This is the first improvement to make and still stay within the bounds of "same" algorithm. It doesn't require any math at all to see this one.
Beyond that, once you see that input is not divisible by 2, there is no need to check for 4, 6, 8, etc. If any even number divided into input, then surely 2 would have because it divides all even numbers.
If you want to step outside of the algorithm a little bit, you could use a loop like the one that Sheldon L. Cooper provides in his answer. (This is just easier than having him correct my code from the comments though his efforts are much appreciated)
this takes advantage of the fact that every prime other than 2 and 3 is of the form n*6 + 1 or n*6 - 1 for some positive integer n. To see this, just note that if m = n*6 + 2 or m = n*6 + 4, then n is divisible by 2. if m = n*6 + 3 then it is divisible by 3.
In fact, we can take this further. If p1, p2, .., pk are the first k primes, then all of the integers that are coprime to their product mark out 'slots' that all remaining primes must fit into.
to see this, just let k# be the product of all primes up to pk. then if gcd(k#, m) = g, g divides n*k# + m and so this sum is trivially composite if g != 1. so if you wanted to iterate in terms of 5# = 30, then your coprime integers are 1, 7, 11, 13, 17, 19, 23 and 29.
technically, I didn't prove my last claim. It's not much more difficult
if g = gcd(k#, m), then for any integer, n, g divides n*k# + m because it divides k# so it must also divide n*k#. But it divides m as well so it must divide the sum. Above I only proved it for n = 1. my bad.
Also, I should note that none of this is changing the fundamental complexity of the algoritm, it will still be O(n^1/2). All it is doing is drastically reducing the coefficient that gets used to calculate actual expected run times.
The time complexity for each primality test in your algorithm is O(sqrt(n)).
You can always use the fact that all primes except 2 and 3 are of the form: 6*k+1 or 6*k-1. For example:
int is_prime(int n) {
if (n <= 1) return 0;
if (n == 2 || n == 3) return 1;
if (n % 2 == 0 || n % 3 == 0) return 0;
int k;
for (k = 6; (k-1)*(k-1) <= n; k += 6) {
if (n % (k-1) == 0 || n % (k+1) == 0) return 0;
}
return 1;
}
This optimization does not improve the asymptotic complexity.
EDIT
Given that in your code you are testing numbers repeatedly, you might want to pre-calculate a list of primes. There are only 4792 primes less than or equal to the square root of INT_MAX (assuming 32 bit ints).
Furthermore, if the input numbers are relatively small you can try calculating a sieve.
Here's a combination of both ideas:
#define UPPER_BOUND 46340 /* floor(sqrt(INT_MAX)) */
#define PRIME_COUNT 4792 /* number of primes <= UPPER_BOUND */
int prime[PRIME_COUNT];
int is_prime_aux[UPPER_BOUND];
void fill_primes() {
int p, m, c = 0;
for (p = 2; p < UPPER_BOUND; p++)
is_prime_aux[p] = 1;
for (p = 2; p < UPPER_BOUND; p++) {
if (is_prime_aux[p]) {
prime[c++] = p;
for (m = p*p; m < UPPER_BOUND; m += p)
is_prime_aux[m] = 0;
}
}
}
int is_prime(int n) {
if (n <= 1) return 0;
if (n < UPPER_BOUND) return is_prime_aux[n];
int i;
for (i = 0; i < PRIME_COUNT && prime[i]*prime[i] <= n; i++)
if (n % prime[i] == 0)
return 0;
return 1;
}
Call fill_primes at the beginning of your program, before starting to process queries. It runs pretty fast.
Your code there only has complexity O(sqrt(n)lg(n)). If you assume basic mathematical operations are O(1) (true until you start using bignums), then it's just O(sqrt(n)).
Note that primality testing can be performed in faster-than-O(sqrt(n)lg(n)) time. This site has a number of implementations of the AKS primality test, which has been proven to operate in O((log n)^12) time.
There are also some very, very fast probalistic tests - while fast, they sometimes give an incorrect result. For example, the Fermat primality test:
Given a number p we want to test for primality, pick a random number a, and test whether a^(p-1) mod p = 1. If false, p is definitely not prime. If true, p is probably prime. By repeating the test with different random values of a, the probability of a false positive can be reduced.
Note that this specific test has some flaws to it - see the Wikipedia page for details, and other probabilistic primality tests you can use.
If you want to stick with the current approach, there are a number of minor improvements which can still be made - as others have pointed out, after 2, all further primes are odd, so you can skip two potential factors at a time in the loop. You can also break out immediately when you find a factor. However, this doesn't change the asymptotic worst-case behavior of your algorithm, which remains at O(sqrt(n)lg(n)) - it just changes the best case (to O(lg(n))), and reduces the constant factor by roughly one-half.
A simple improvement would be to change the for loop to break out when it finds a factor:
for (i = 2; i <= ceiling && !factorFound; i++) {
if (input % i == 0) {
factorFound = 1;
Another possibility would be to increment the counter by 2 (after checking 2 itself).
can you suggest an improvement
Here you go ... not for the algorithm, but for the program itself :)
If you aren't going to use argc and argv, get rid of them
What if I input "fortytwo"? Compare scanf() == 1, not != EOF
No need to cast the value of sqrt()
returnValue is not needed, you can return a constant: return 0;
Instead of having all of the functionality inside the main() function, separate your program in as many functions as you can think of.
You can make small cuts to your algorithm without adding too much code complexity.
For example, you can skip the even numbers on your verification, and stop the search as soon as you find a factor.
if (input < 2 || (input != 2 && input % 2 == 0))
factorFound = 1;
if (input > 3)
for (i = 3; i <= ceiling && !factorFound; i += 2)
if (input % i == 0)
factorFound = 1;
Regarding the complexity, if n is your input number, wouldn't the complexity be O(sqrt(n)), as you are doing roughly at most sqrt(n) divisions and comparisons?
Even numbers(except 2) cannot be prime numbers. So, once we know that the number is not even, we can just check if odd numbers are it's factors.
for (i = 3; i <= ceiling; i += 2) {
if (input % i == 0) {
factorFound = 1;
break;
}
}
The time complexity of your program is O(n*m^0.5). With n the number of primes in the input. And m the size of the biggest prime in the input, or MAX_INT if you prefer. So complexity could also be written as O(n) with n the number of primes to check.
With Big-O, n is (usually) the size of the input, in your case that would be the number of primes to check. If I make this list twice as big (for example duplicating it), it would take (+-) exactly twice as long, thus O(n).
Here's my algorithm, Complexity remains O(n^0.5) but i managed to remove some expensive operations in the code...
The algorithm's slowest part is the modulus operation, i've managed to eliminate sqrt or doing i * i <= n
This way i save precious cycles...its based on the fact that sum of odd numbers is always a perfect square.
Since we are iterating over odd numbers anyway, why not exploit it? :)
int isPrime(int n)
{
int squares = 1;
int odd = 3;
if( ((n & 1) == 0) || (n < 9)) return (n == 2) || ((n > 1) && (n & 1));
else
{
for( ;squares <= n; odd += 2)
{
if( n % odd == 0)
return 0;
squares+=odd;
}
return 1;
}
}
#include <stdio.h>
#include <math.h>
int IsPrime (int n) {
int i, sqrtN;
if (n < 2) { return 0; } /* 1, 0, and negatives are nonprime */
if (n == 2) { return 2; }
if ((n % 2) == 0) { return 0; } /* Check for even numbers */
sqrtN = sqrt((double)n)+1; /* We don't need to search all the way up to n */
for (i = 3; i < sqrtN; i += 2) {
if (n % i == 0) { return 0; } /* Stop, because we found a factor! */
}
return n;
}
int main()
{
int n;
printf("Enter a positive integer: ");
scanf("%d",&n);
if(IsPrime(n))
printf("%d is a prime number.",n);
else
printf("%d is not a prime number.",n);
return 0;
}
There is no way to improve the algorithm. There may be tiny ways to improve your code, but not the base speed (and complexity) of the algorithm.
EDIT: Of course, since he doesn't need to know all the factors, just whether or not it is a prime number. Great spot.

Resources