我最好的选择是在表演时不会因为特殊的演习而过度。
的Erathostenes'钛硅分子筛 - 在的下面复杂度为O(N *日志(日志(N))) - 由于内j
循环从i*i
代替i
开始。
#include <vector>
using std::vector;
void erathostenes_sieve(size_t upToN, vector<size_t>& primes) {
primes.clear();
vector<bool> bitset(upToN+1, true); // if the bitset[i] is true, the i is prime
bitset[0]=bitset[1]=0;
// if i is 2, will jump to 3, otherwise will jump on odd numbers only
for(size_t i=2; i<=upToN; i+=((i&1) ? 2 : 1)) {
if(bitset[i]) { // i is prime
primes.push_back(i);
// it is enough to start the next cycle from i*i, because all the
// other primality tests below it are already performed:
// e.g:
// - i*(i-1) was surely marked non-prime when we considered multiples of 2
// - i*(i-2) was tested at (i-2) if (i-2) was prime or earlier (if non-prime)
for(size_t j=i*i; j<upToN; j+=i) {
bitset[j]=false; // all multiples of the prime with value of i
// are marked non-prime, using **addition only**
}
}
}
}
现在保基础上,primes
(在组排序矢量)。在此之前,让我们来看看sqrt
的神话价格昂贵,但大量的乘法不是。
首先,让我们注意到,sqrt is not that expensive anymore:旧的CPU-ES上(86/32B),它使用的是贵一倍的分裂(和modulo
操作为师),在新架构的CPU成本是平等的。由于因式分解一次又一次地都是大约%
操作,所以人们现在仍然可以考虑sqrt
(例如,如果和当使用它时节省CPU时间)。
例如,考虑用于N=65537
下面的代码(其是6553个素数)假定primes
具有10000 entries
size_t limit=std::sqrt(N);
size_t largestPrimeGoodForN=std::distance(
primes.begin(),
std::upper_limit(primes.begin(), primes.end(), limit) // binary search
);
// go descendingly from limit!!!
for(int i=largestPrimeGoodForN; i>=0; i--) {
// factorisation loop
}
我们有:
- 1 SQRT(等于1
modulo
) ,
- 1在
10000
条目中搜索 - 最多14个步骤,每个包含1个比较,1个右移2分频和1个递增/递减 - s我们假设一个等于14-20次乘法的成本(如果有的话)
- 由于
std::distance
的差异。
因此,最大的成本 - 1格和20毫秒?我很慷慨。
在另一边:
for(int i=0; primes[i]*primes[i]<N; i++) {
// factorisation code
}
看起来简单得多,但是作为N=65537
是素数,我们将通过所有的周期可达i=64
(我们会在第一黄金造成循环打破) - 总共65次乘法。
用一个更高的素数尝试一下,我保证1 sqrt + 1的二进制搜索的代价更好地利用了CPU周期比所有乘法中的更简单形式的周期吹捧为更好的性能解决方案
所以,回到因式分解代码:
#include <algorithm>
#include <math>
#include <unordered_map>
void factor(size_t N, std::unordered_map<size_t, size_t>& factorsWithMultiplicity) {
factorsWithMultiplicity.clear();
while(!(N & 1)) { // while N is even, cheaper test than a '% 2'
factorsWithMultiplicity[2]++;
N = N >> 1; // div by 2 of an unsigned number, cheaper than the actual /2
}
// now that we know N is even, we start using the primes from the sieve
size_t limit=std::sqrt(N); // sqrt is no longer *that* expensive,
vector<size_t> primes;
// fill the primes up to the limit. Let's be generous, add 1 to it
erathostenes_sieve(limit+1, primes);
// we know that the largest prime worth checking is
// the last element of the primes.
for(
size_t largestPrimeIndexGoodForN=primes.size()-1;
largestPrimeIndexGoodForN<primes.size(); // size_t is unsigned, so after zero will underflow
// we'll handle the cycle index inside
) {
bool wasFactor=false;
size_t factorToTest=primes[largestPrimeIndexGoodForN];
while(!(N % factorToTest)) {
wasFactor=true;// found one
factorsWithMultiplicity[factorToTest]++;
N /= factorToTest;
}
if(1==N) { // done
break;
}
if(wasFactor) { // time to resynchronize the index
limit=std::sqrt(N);
largestPrimeIndexGoodForN=std::distance(
primes.begin(),
std::upper_bound(primes.begin(), primes.end(), limit)
);
}
else { // no luck this time
largestPrimeIndexGoodForN--;
}
} // done the factoring cycle
if(N>1) { // N was prime to begin with
factorsWithMultiplicity[N]++;
}
}
你能举个例子说明你在找什么吗?例如,如果'x = 12',那么唯一因子的数目是'6'(1,2,3,4,6,12),而'n = 12 * 6 = 72'?或者你想计算素数因子('2 * 2 * 3'),在这种情况下'n = 12 * 3 = 36'? – Holt
大数字是什么意思?你能告诉N的范围吗? – vish4071
[为什么“使用命名空间std”被认为是不好的做法?](http://stackoverflow.com/q/1452721/995714)。你应该包括[''和''(http://stackoverflow.com/q/15656434/995714),而不是'stdio.h'和'math.h' –