Problem in proper divisor algo - c

I wrote two algos to get the sum of the proper divisors of a given number,to find perfect number or abundant number.
long sum_divisors_1(int a)
{
int i, t;
long sum = 1;
for (i = 2, t = sqrt(a); i < t + 1; i++) {
if (a % i == 0) {
sum += i;
sum += a / i;
}
}
if (a % t == 0)
sum -= t;
return sum;
}
long sum_divisors_2(int a)
{
int i, sum;
sum = 0;
for (i = 1; i < (int) (a / 2 + 1); i++) {
if (a % i == 0)
sum += i;
}
return sum;
}
And I think they are both correct and the first one is faster. But I can only get the correct result from the second algo. Other parts of the code are the same.
Any suggestions? And how the proper divisors are found in real industrial programming?
Thanks in advance.

Your problem lies here:
if (a % t == 0)
sum -= t;
Since you're casting t to an int from a floating point, it will round down to an integer value. This also assumes that t is the actual square root when it isn't. This will evaluate to true when a number has factors x & x+1 (the unit test I posted as well fails when i = 6 because it's square root is 2.45 and 2 is a factor).
The check really should be:
if (t*t == a)
sum -= t;

This is an old question but I was browsing.
There's a much faster algorithm to find the sum of proper divisors.
Find the prime factors of a number using Sieve of Eratosthenes (or Atkin). With wheel factorisation the first 1m prime numbers will take maybe 30ms.
Then the sum of all divisors is
For each n
sum += (n ^ (m+1) - 1) / (n-1)
where n is the factor, m is the power of that factor.
Eg for 220
2^2 5 11 are the factors
So it's sum of
2 ^ (2+1) - 1 / 1 *
5 ^ (1+1) - 1 / 4 *
11 ^ (1+1) - 1 / 10
= 7 * 6 * 12
= 504
This is the sum of ALL divisors, so just subtract N
504-220 = 284
This should be a lot faster than trying all the numbers, especially if you precalculate the sieve and reuse it.

Here's a simple unit test I wrote in C# that will quickly invalidate #1 given #2 is correct:
for(int i = 4; i < 28124; i++)
{
Assert.AreEqual(sum_divisors_2(i), sum_divisors_1(i), "Failed when i = {0}", i);
}
Too big for a comment...

Templatetypedef solved your problem; however the fastest possible way to compute the prime factors is to precompute all the prime factors up to sqrt(MAX_INT) with Eratostene sieve, store it into an array and then use it to factorize the number a. This is really really really much faster.

Related

How can i get the sum of the numbers produced by a loop

do
{
sum = ((card % x) / y) * 2;
if (sum >= 10)
{
sum = sum % 10 + (sum % 100) / 10;
}
printf("%ld\n", sum);
x *= 100;
y *= 100;
}
while (x <= 10000000000000000);// calculates every other digit multiplied by 2
output:
2
0
0
0
0
3
0
8
I need to get the sum which is 13 in this case.
I'm a beginner and been stuck on this for a while, a little help would be appreciated. thanks
Add another variable that accumulates the total.
long int total = 0;
do
{
sum = ((card % x) / y) * 2;
if (sum >= 10)
{
sum = sum % 10 + (sum % 100) / 10;
}
printf("%ld\n", sum);
total += sum;
x *= 100;
y *= 100;
}
while (x <= 10000000000000000);// calculates every other digit multiplied by 2
printf("Total = %ld\n", total);
There are many ways of going at this, but I suggest that you look into recursive functions--since you mentioned you are a beginner. After years of coding in C, I find myself implementing recursive functions most naturally on these types of tasks.
I acknowledge that you mentioned using while loop. You can still use recursion to do the exact same thing you are trying to achieve with the loop by using if statement. Also, I would pass in the variables you use in the recursive function parameter.
There are thousands of tutorials and examples of recursion online. I highly recommend you get familiar with them. Cheers!

sum's sum of divizors of numbers less than or equal to N

I really need some help at this problem:
Given a positive integer N, we define xsum(N) as sum's sum of all positive integer divisors' numbers less or equal to N.
For example: xsum(6) = 1 + (1 + 2) + (1 + 3) + (1 + 2 + 4) + (1 + 5) + (1 + 2 + 3 + 6) = 33.
(xsum - sum of divizors of 1 + sum of divizors of 2 + ... + sum of div of 6)
Given a positive integer K, you are asked to find the lowest N that satisfies the condition: xsum(N) >= K
K is a nonzero natural number that has at most 14 digits
time limit : 0.2 sec
Obviously, the brute force will fall for most cases with Time Limit Exceeded. I haven't find something better than it yet, so that's the code:
fscanf(fi,"%lld",&k);
i=2;
sum=1;
while(sum<k) {
sum=sum+i+1;
d=2;
while(d*d<=i) {
if(i%d==0 && d*d!=i)
sum=sum+d+i/d;
else
if(d*d==i)
sum+=d;
d++;
}
i++;
}
Any better ideas?
For each number n in range [1 , N] the following applies: n is divisor of exactly roundDown(N / n) numbers in range [1 , N]. Thus for each n we add a total of n * roundDown(N / n) to the result.
int xsum(int N){
int result = 0;
for(int i = 1 ; i <= N ; i++)
result += (N / i) * i;//due to the int-division the two i don't cancel out
return result;
}
The idea behind this algorithm can aswell be used to solve the main-problem (smallest N such that xsum(N) >= K) in faster time than brute-force search.
The complete search can be further optimized using some rules we can derive from the above code: K = minN * minN (minN would be the correct result if K = 2 * 3 * ...). Using this information we have a lower-bound for starting the search.
Next step would be to search for the upper bound. Since the growth of xsum(N) is (approximately) quadratic we can use this to approximate N. This optimized guessing allows to find the searched value pretty fast.
int N(int K){
//start with the minimum-bound of N
int upperN = (int) sqrt(K);
int lowerN = upperN;
int tmpSum;
//search until xsum(upperN) reaches K
while((tmpSum = xsum(upperN)) < K){
int r = K - tmpSum;
lowerN = upperN;
upperN += (int) sqrt(r / 3) + 1;
}
//Now the we have an upper and a lower bound for searching N
//the rest of the search can be done using binary-search (i won't
//implement it here)
int N;//search for the value
return N;
}

finding number of numbers which have prime number of factors

The problem is to find the number of divisors of a number
ex-
for 10
ans=4
since 1,2,5,10 are the numbers which are divisors
i.e. they are the factors
constraints are num<=10^6
I have implemented a code for the same but got TLE!!
here is my code
int isprime[MAX];
void seive()
{
int i,
j;
isprime[0] = isprime[1] = 1;
for (i = 4; i < MAX; i += 2)
isprime[i] = 1;
for (i = 3; i * i < MAX; i += 2) {
if (!isprime[i]) {
for (j = i * i; j < MAX; j += 2 * i)
isprime[j] = 1;
}
}
}
int main()
{
seive();
int t;
long long num;
scanf("%d", & t);
while (t--) {
scanf("%lld", & num);
cnt = 0;
for (j = 1; j * j <= num; j++) {
if (num % j == 0) {
cnt++;
if (num / j != j)
cnt++;
}
printf("%lld\n", cnt);
}
return 0;
}
Can somebody help me to optimize it?
I have also searched about it but didnot getting any sucess.
So Please help guys.
You could try computing this mathematically (I'm not sure this will be faster/easier). Basically, given the prime factorization of a number, you should be able to calculate the number of divisors without too much trouble.
If you have an input x decompose into something like
x = p1^a1 * p2^a2 * ... pn^an
Then the number of divisors should be
prod(ai + 1) for i in 1 to n
I would then look at finding the smallest prime < sqrt(x), dividing that out until you're left with just a prime. A sieve might still be useful and I don't know what kind of input you would be getting.
Now consider what the above statement says: the number of divisors in the product of the powers of the prime factorization (plus 1). Thus, if you only every care if the result is prime, then you should only ever consider numbers which are prime, or powers of primes. And within that, you then only need to consider powers such that a1 + 1 is prime.
That should significantly cut down your search space.
If the prime factorization of a number is:
x = p1^e1 * p2^e2 * ... * pk^ek
Then the number of divisors is:
(e1 + 1)*(e2 + 1)* ... *(ek + 1)
For this to be prime, you need all ei to be 0, except one, which needs to be a prime - 1.
This is only true for primes and powers of primes. So you need to find how many powers of primes are in [l, r]. For example, 2^6 has (6 + 1) = 7 prime factors.
Now you just need to sieve enough primes fast enough. You only need to sieve those in [l, r], so an interval of size max 10^6.
To sieve directly in this interval, remove multiples of 2 directly from [l, r], and same for the rest. You can sieve primes up to 10^6 and use those to do the interval sieving later.
You can do the necessary counting while you're sieving as well.

Fast Prime Factorization Algorithm

I'm writing a code in C that returns the number of times a positive integer can be expressed as sums of perfect squares of two positive integers.
R(n) is the number of couples (x,y) such that x² + y² = n where x, y, n are all
non negative integers.
To compute R(n), I need to first find the prime factorization of n.
The problem is that I've tried a lot of algorithm for prime factorization that I can use on C but I need my code to be as fast as possible, so I would appreciate it if anyone can give me what he/she considers as the fastest algorithm to compute the prime factorization of a number as large as 2147483742.
What an odd limit; 2147483742 = 2^31 + 94.
As others have pointed out, for a number this small trial division by primes is most likely fast enough. Only if it isn't, you could try Pollard's rho method:
/* WARNING! UNTESTED CODE! */
long rho(n, c) {
long t = 2;
long h = 2;
long d = 1;
while (d == 1) {
t = (t*t + c) % n;
h = (h*h + c) % n;
h = (h*h + c) % n;
d = gcd(t-h, n); }
if (d == n)
return rho(n, c+1);
return d;
}
Called as rho(n,1), this function returns a (possibly-composite) factor of n; put it in a loop and call it repeatedly if you want to find all the factors of n. You'll also need a primality checker; for your limit, a Rabin-Miller test with bases 2, 7 and 61 is proven accurate and reasonably fast. You can read more about programming with prime numbers at my blog.
But in any case, given such a small limit I think you are better off using trial division by primes. Anything else might be asymptotically faster but practically slower.
EDIT: This answer has received several recent upvotes, so I'm adding a simple program that does wheel factorization with a 2,3,5-wheel. Called as wheel(n), this program prints the factors of n in increasing order.
long wheel(long n) {
long ws[] = {1,2,2,4,2,4,2,4,6,2,6};
long f = 2; int w = 0;
while (f * f <= n) {
if (n % f == 0) {
printf("%ld\n", f);
n /= f;
} else {
f += ws[w];
w = (w == 10) ? 3 : (w+1);
}
}
printf("%ld\n", n);
return 0;
}
I discuss wheel factorization at my blog; the explanation is lengthy, so I won't repeat it here. For integers that fit in a long, it is unlikely that you will be able to significantly better the wheel function given above.
There's a fast way to cut down the number of candidates. This routine tries 2, then 3, then all the odd numbers not divisible by 3.
long mediumFactor(n)
{
if ((n % 2) == 0) return 2;
if ((n % 3) == 0) return 3;
try = 5;
inc = 2;
lim = sqrt(n);
while (try <= lim)
{
if ((n % try) == 0) return try;
try += inc;
inc = 6 - inc; // flip from 2 -> 4 -> 2
}
return 1; // n is prime
}
The alternation of inc between 2 and 4 is carefully aligned so that it skips all even numbers and numbers divisible by 3. For this case: 5 (+2) 7 (+4) 11 (+2) 13 (+4) 17
Trials stop at sqrt(n) because at least one factor must be at or below the square root. (If both factors were > sqrt(n) then the product of the factors would be greater than n.)
Number of tries is sqrt(m)/3, where m is the highest possible number in your series. For a limit of 2147483647, that yields a maximum of 15,448 divisions worst case (for a prime near 2147483647) including the 2 and 3 tests.
If the number is composite, total number of divisions is usually much less and will very rarely be more; even taking into account calling the routine repeatedly to get all the factors.

Finding prime factors in C

I am trying to generate all the prime factors of a number n. When I give it the number 126 it gives me 2, 3 and 7 but when I give it say 8 it gives me 2, 4 and 8. Any ideas as to what I am doing wrong?
int findPrime(unsigned long n)
{
int testDivisor, i;
i = 0;
testDivisor = 2;
while (testDivisor < n + 1)
{
if ((testDivisor * testDivisor) > n)
{
//If the test divisor squared is greater than the current n, then
//the current n is either 1 or prime. Save it if prime and return
}
if (((n % testDivisor) == 0))
{
prime[i] = testDivisor;
if (DEBUG == 1) printf("prime[%d] = %d\n", i, prime[i]);
i++;
n = n / testDivisor;
}
testDivisor++;
}
return i;
}
You are incrementing testDivisor even when you were able to divide n by it. Only increase it when it is not divisible anymore. This will result in 2,2,2, so you have to modify it a bit further so you do not store duplicates, but since this is a homework assignment I think you should figure that one out yourself :)
Is this based on an algorithm your professor told you to implement or is it your own heuristic? In case it helps, some known algorithms for prime factorization are the Quadratic Sieve and the General Number Field Sieve.
Right now, you aren't checking if any divisors you find are prime. As long as n % testDivisor == 0 you are counting testDivisor as a prime factor. Also, you are only dividing through by testDivisor once. You could fix this a number of ways, one of which would be to replace the statement if (((n % testDivisor) == 0)) with while (((n % testDivisor) == 0)).
Fixing this by adding the while loop also ensures that you won't get composite numbers as divisors, as if they still divide n, a smaller prime factor must have also divided n and the while loop for that prime factor wouldn't have left early.
Here is code to find the Prime Factor:
long GetPrimeFactors(long num, long *arrResult)
{
long count = 0;
long arr[MAX_SIZE];
long i = 0;
long idx = 0;
for(i = 2; i <= num; i++)
{
if(IsPrimeNumber(i) == true)
arr[count++] = i;
}
while(1)
{
if(IsPrimeNumber(num) == true)
{
arrResult[idx++] = num;
break;
}
for(i = count - 1; i >= 0; i--)
{
if( (num % arr[i]) == 0)
{
arrResult[idx++] = arr[i];
num = num / arr[i];
break;
}
}
}
return idx;
}
Reference: http://www.softwareandfinance.com/Turbo_C/Prime_Factor.html
You can use the quadratic sieve algorithm, which factors 170-bit integers in second and 220-bit integers in minute. There is a pure C implementation here that does not require GMP or an external library : https://github.com/michel-leonard/C-Quadratic-Sieve, it's able to provide you a list of the prime factors of N. Thank You.

Resources