我想找到给定数字的最大素数因子。经过多次尝试,我已经增强了测试以应对相当大的数字(即以毫秒为单位)。现在的问题是,如果超过10亿,执行时间将永远存在,可以这么说。我想知道我是否可以做更多改进并缩短执行时间。我希望有更好的执行时间,因为在这个链接Prime Factors Calculator中,执行时间非常快。我此时的目标号码是600851475143.代码相当不言自明。 注意:我已经考虑了Eratosthenes算法的Sieve,但没有关于执行时间的运气。
#include <iostream>
#include <cmath>
bool isPrime(int n)
{
if (n==2)
return true;
if (n%2==0)
return false;
for (int i(3);i<=sqrt(n);i+=2) // ignore even numbers and go up to sqrt(n)
if (n%i==0)
return false;
return true;
}
int main()
{
int max(0);
long long target(600851475143);
if( target%2 == 0 )
max = 2;
for ( int i(3); i<target; i+=2 ){ // loop through odd numbers.
if( target%i == 0 ) // check for common factor
if( isPrime(i) ) // check for prime common factor
max = i;
}
std::cout << "The greatest prime common factor is " << max << "\n";
return 0;
}
答案 0 :(得分:3)
我可以看到一个明显的优化:
for (int i(3);i<=sqrt(n);i+=2) // ignore even numbers and go up to sqrt(n)
每次你可以将结果缓存到变量中时,而不是计算sqrt
。
auto maxFactor = static_cast<int>sqrt(n);
for (int i(3); i <= maxFactor; i+=2);
我认为这可能导致加速的原因是sqrt
处理floating point arithematic
并且编译器通常并不慷慨地优化浮点数。 gcc有一个特殊的标志ffast-math,可以明确地启用浮点优化。
对于您提到的目标范围以外的数字,您需要更好的算法。 repeated divisioning应该足够了。
以下代码(http://ideone.com/RoAmHd)几乎没有时间完成:
int main() {
long long input = 600851475143;
long long mx = 0;
for (int x = 2; x <= input/x; ++x){
while(input%x==0) {input/=x; mx = x; }
}
if (input > 1){
mx = input;
}
cout << mx << endl;
return 0;
}
重复划分背后的想法是,如果数字已经是 p 的因子,它也是 p ^ 2,p ^ 3,p ^ 4的因子.... 即可。因此,我们继续消除因素,因此只有最终因素仍然存在才能最终划分数字。
答案 1 :(得分:1)
你不需要进行素性测试。试试这个算法:
function factors(n)
f := 2
while f * f <= n
if n % f == 0
output f
n := n / f
else
f := f + 1
output n
您不需要素性测试,因为每个步骤的试验因子增加1,因此任何复合试验因子都已经由其较小的组成素数处理。
我将留给您使用适当的数据类型在C ++中实现。这不是计算整数的最快方法,但对于Project Euler 3来说已经足够了。
答案 2 :(得分:0)
请注意,除2和3外,所有素数都与6的倍数相邻。
以下代码通过以下方式减少了迭代总数:
target
#include <iostream>
bool CheckFactor(long long& target,long long factor)
{
if (target%factor == 0)
{
do target /= factor;
while (target%factor == 0);
return true;
}
return false;
}
long long GetMaxFactor(long long target)
{
long long maxFactor = 1;
if (CheckFactor(target,2))
maxFactor = 2;
if (CheckFactor(target,3))
maxFactor = 3;
// Check only factors that are adjacent to multiples of 6
for (long long factor = 5, add = 2; factor*factor <= target; factor += add, add = 6-add)
{
if (CheckFactor(target,factor))
maxFactor = factor;
}
if (target > 1)
return target;
return maxFactor;
}
int main()
{
long long target = 600851475143;
std::cout << "The greatest prime factor of " << target << " is " << GetMaxFactor(target) << std::endl;
return 0;
}
答案 3 :(得分:0)
for ( int i(3); i<target; i+=2 ){ // loop through odd numbers.
if( target%i == 0 ) // check for common factor
if( isPrime(i) ) // check for prime common factor
max = i;
这是此代码的前两行,而不是素数检查,几乎占用了所有时间。您将目标划分为从3
到target-1
的所有数字。这需要大约target/2
个分区。
此外,target
为long long
,而i
仅为int
。尺寸太小可能会导致无限循环。
最后,此代码不计算最大的主要公因子。它计算目标的最大质数除数,并且效率非常低。那么你真正需要什么?
任何事情都是一个坏主意&#34; max&#34;在c ++中,因为max是一个标准函数。
答案 4 :(得分:0)
这是我的基本版本:
int main() {
long long input = 600851475143L;
long long pMax = 0;
// Deal with prime 2.
while (input % 2 == 0) {
input /= 2;
pMax = 2;
}
// Deal with odd primes.
for (long long x = 3; x * x <= input; x += 2) {
while (input % x == 0) {
input /= x;
pMax = x;
}
}
// Check for unfactorised input - must be prime.
if (input > 1) {
pMax = input;
}
std::cout << "The greatest prime common factor is " << pMax << "\n";
return 0;
}
通过使用Newton-Raphson整数平方根方法为循环设置(大部分)固定限制,可以进一步加快速度。如果可用,则需要重写主循环。
long long limit = iSqrt(input)
for (long long x = 3; x <= limit; x += 2) {
if (input % x == 0) {
pMax = x;
do {
input /= x;
} while (input % x == 0);
limit = iSqrt(input); // Value of input changed so reset limit.
}
}
只有在找到新因子并且input
的值发生变化时,才会计算平方根。