unsigned int* factor(unsigned int n)
が典型的な 32 ビット タイプである場合unsigned int
、数値が小さすぎて、より高度なアルゴリズムを実行できません。トライアル部門の通常の強化はもちろん価値があります。
Pete Becker で述べられているように、ループから除算を 2 で除算し、ループ内で奇数のみで除算する場合、基本的に、入力数値を因数分解するために必要な除算の数が半分になり、速度が向上します。関数はほぼ 2 倍になります。
これをさらに一歩進めて、ループ内の除数から 3 の倍数を取り除くと、除算の数が減るため、速度が 3 倍に近くなります (平均して、ほとんどの数値には大きな値はありません)。素因数ですが、2 または 3 で割り切れますが、これらの素因数分解の速度ははるかに小さくなりますが、これらの数は素因数分解が速くなります。素約数が大きい場合)。
// if your compiler doesn't transform that to bit-operations, do it yourself
while(n % 2 == 0) {
tab[dim++] = 2;
n /= 2;
}
while(n % 3 == 0) {
tab[dim++] = 3;
n /= 3;
}
for(int d = 5, s = 2; d*d <= n; d += s, s = 6-s) {
while(n % d == 0) {
tab[dim++] = d;
n /= d;
}
}
その関数を非常に頻繁に呼び出す場合は、65535 を超えない 6542 の素数を事前に計算し、それらを静的配列に格納し、素数のみで除算して、除数を見つけられないことがアプリオリに保証されているすべての除算を排除することをお勧めします。 .
unsigned int
たまたま 32 ビットより大きい場合は、より高度なアルゴリズムの 1 つを使用すると有益です。小さな素因数を見つけるために試行分割から始める必要があります (小さな素因数が<= 1000
、<= 10000
、<= 100000
またはおそらく<= 1000000
テストする必要があるかどうかにかかわらず、私の直感では、小さな値の 1 つが平均的に優れていると思います)。試行分割フェーズの後、因数分解がまだ完了していない場合は、残りの因数が素数であるかどうかを確認します。たとえば、Miller-Rabin 検定の決定論的 (問題の範囲の) バリアントを使用します。そうでない場合は、お気に入りの高度なアルゴリズムを使用して要因を検索します。64 ビットの数値の場合、Pollard の rho アルゴリズムをお勧めしますまたは楕円曲線因数分解。Pollard の rho アルゴリズムは実装がより簡単で、その大きさの数に対して同等の時間で要因を見つけることができるため、これが私の最初の推奨事項です。