问题
I have to find the the total number of divisors of a given number N where can be as large as 10^14 .I tried out calculating the primes upto 10^7 and then finding the the divisors using the exponents of the prime factors.However it is turning out to be too slow as finding the primes using the sieve takes 0.03 s. How can I calculate the total number of divisors faster and if possible without calculating the primes? Please pseudo code /well explained algorithm will be greatly appreciated.
回答1:
Use the sieve of atkin to find all of primes less than 10^7. (there are 664,579 of these)
http://en.wikipedia.org/wiki/Sieve_of_Atkin
ideally this should be done at compile time.
next compute the prime factorization:
int x; // the number you want to factor
Map<int to int> primeFactor; // this is a map that will map each prime that appears in the prime factorization to the number of times it appears.
while(x > 1) {
for each prime p <= x {
if x % p == 0 {
x = x / p;
primeFactor(p) = primeFactor(p) +1;
}
}
}
At the end of this, you will have the complete prime factorization. From this you can compute the total number of divisors by iterating over the values of the map: https://math.stackexchange.com/questions/66054/number-of-combinations-of-a-multiset-of-objects
int result = 1;
for each value v in primeFactors {
result*= (v+1);
}
回答2:
I implemented the Sieve of Atkin at my blog, but still found an optimized Sieve of Eratosthenes to be faster.
But I doubt that's your problem. For numbers as large as 10^14, Pollard rho factorization will beat trial division by primes, no matter how you generate the primes. I did that at my blog, too.
回答3:
You can use Pollard's rho-algorithm for factorization. With all the improvements it is quick for numbers up to at least 10^20.
Here is my implementation for finding a factor in Java:
/**
* Finds a factor of a number using Brent's algorithm.
*
* @param n The number.
*
* @return A factor of n.
*/
public static BigInteger findFactor(BigInteger n)
{
final BigInteger result;
if (n.isProbablePrime(80))
{
result = n;
}
else
{
BigInteger gcd = n;
BigInteger c = ONE;
while (gcd.equals(n))
{
int limitPower = 0;
long k = 0;
BigInteger y = ONE;
boolean done = false;
while (!done)
{
limitPower++;
final long limit = Numbers.pow(2, limitPower);
final int productLimit = (int) Numbers.pow(2, limitPower / 2);
final BigInteger x = y;
while (!done && k < limit)
{
final BigInteger savedY = y;
int j = 0;
final int jLimit = (int) Math.min(productLimit, limit - k);
BigInteger p = ONE;
while (j < jLimit)
{
y = next(n, c, y);
p = p.multiply(x.subtract(y)).mod(n);
j++;
}
gcd = Numbers.gcd(p, n);
if (gcd.equals(ONE))
{
// Move along, nothing to be seen here
k += jLimit;
}
else
{
// Restart and find the factor
y = savedY;
while (!done)
{
k++;
y = next(n, c, y);
gcd = Numbers.gcd(x.subtract(y), n);
done = !gcd.equals(ONE);
}
}
}
}
c = c.add(ONE);
}
result = gcd;
}
return result;
}
private static BigInteger next(BigInteger m, BigInteger c, BigInteger x)
{
return square(x).subtract(c).mod(m);
}
To factorize numbers up to 1014 you could also just do trial division with odd numbers up to 107.
来源:https://stackoverflow.com/questions/12288671/how-can-i-write-a-fast-function-to-calculate-total-divisors-of-a-number