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.
Related
I'm struggling to find the time complexity of this function:
void foo(int n) {
int i, m = 1;
for (i = 0; i < n; i++) {
m *= n; // (m = n^n) ??
}
while (m > 1) {
m /= 3;
}
}
Well, the first for iteration is clearly O(n^n), the explanation to it is because m started with value 1, and multiplies itself n times.
Now, we start the while loop with m = n^n and we divide it every time by 3.
which means, (I guess), log(n^n).
Assuming I got it right up till now, I'm not sure if I need to sum or multiply, but my logic says I need to sum them, because they are 'odd' to each other.
So my assumption is: O(n^n) + O(log(n^n)) = O(n^n) Because if n is quite big, we can just refrain from O(log(n^n)).
Well, I really made many assumptions here, and I hope that makes sense. I'd love to hear your opinions about the time complexity of this function.
Theoretically, time complexity is O(n log n) because:
for (i=0; i<n; i++)
m *= n;
this will be executed n times and in the end m=n^n
Then this
while (m>1)
m /= 3;
will be executed log3(n^n) times which is n * log3(n):
P.S. But this is only if you count number of operations. In real life it takes much more time to calculate n^n because the numbers become too big. Also your function will overflow when you will be multiplying such big numbers and most probably you will be bounded by the maximum number of int (in which case the complexity will be O(n))
With foo(int n) and 32-bit int, n cannot exceed the magnitude of 10, else m *= n overflows.
Given such a small range that n works, the O() seems moot. Even with 64-bit unsigned m, n <= 15.
So I suppose O(n lg(n)) is technically correct, but given the constraints of int, suspect code took more time to do a single printf() than iterate through foo(10). IOWs it is practically O(1).
unsigned long long foo(int n) {
unsigned long long cnt = 0;
int i;
unsigned long long m = 1;
for (i = 0; i < n; i++) {
if (m >= ULLONG_MAX/n) exit(1);
m *= n; // (m = n^n) ??
cnt++;
}
while (m > 1) {
m /= 3;
cnt++;
}
return cnt;
}
And came up with
1 1
2 3
3 6
4 9
5 12
6 16
7 19
8 23
9 27
10 31
11 35
12 39
13 43
14 47
15 52
In the lecture, we were told that there is at least one prime number between k³ and (k + 1)³ for all k > 1. I would now like to know how to find such a prime number efficiently in C. I know the Sieve of Eratosthenes yet I have no clue how to implement it without polluting memory. Thanks for your help.
You need to pollute your memory to increase the speed of finding the prime number. There is a simple approach that is fast and simple to implement.
primes = list of prime number below sqrt( (k+1)^3 )
for i = k^3 + 1 to (k+1)^3 :
is_prime = true
for p in primes:
if (i % p == 0) :
is_prime = false
break
if (is_prime):
print(i)
For generating the list of prime number below sqrt ( (k+1)^3 ), you can use Sieve of Eratosthenes. With this approach, you will only need to use at most (k+1)1.5 of memory.
The answer depends very much on the size of k. If k is small, less than 10**3 or thereabouts, the Sieve of Eratosthenes will work well. But if k is larger, a better approach is to use a Miller-Rabin pseudoprimality test:
function isPrime(n, k=5)
if n < 2 then return False
for p in [2,3,5,7,11,13,17,19,23,29]
if n % p == 0 then return n == p
s, d = 0, n-1
while d % 2 == 0
s, d = s+1, d/2
for i from 0 to k
x = powerMod(randint(2, n-1), d, n)
if x == 1 or x == n-1 then next i
for r from 1 to s
x = (x * x) % n
if x == 1 then return False
if x == n-1 then next i
return False
return True
With that, you can test each odd number starting at k cubed. It shouldn't take long to find a prime.
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.
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.
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.