我试图在C中找到一个巨大数字的最大素数因子,对于像100或甚至10000这样的小数字,它工作正常但失败(失败,我的意思是它保持运行和运行对于非常大的target
数字,我的core2duo和i5)需要几十分钟(请参阅目标编号的代码。)
我的算法是否正确?
我是C的新手并且真的在与大数字竞争。我想要的是纠正或指导而不是解决方案我可以使用python与bignum绑定和东西(我还没有尝试但非常确定)但不在C中。或者我可能做了一些这个小错误,我太累了,无论如何,这里是我写的代码:
#include <stdio.h>
// To find largest prime factor of target
int is_prime(unsigned long long int num);
long int main(void) {
unsigned long long int target = 600851475143;
unsigned long long int current_factor = 1;
register unsigned long long int i = 2;
while (i < target) {
if ( (target % i) == 0 && is_prime(i) && (i > current_factor) ) { //verify i as a prime factor and greater than last factor
current_factor = i;
}
i++;
}
printf("The greates is: %llu \n",current_factor);
return(0);
}
int is_prime (unsigned long long int num) { //if num is prime 1 else 0
unsigned long long int z = 2;
while (num > z && z !=num) {
if ((num % z) == 0) {return 0;}
z++;
}
return 1;
}
答案 0 :(得分:4)
通过迭代直到数字的平方根,我们可以得到它的所有因素。(factor
和N/factor
以及factor<=sqrt(N)
)。在这个小想法下,解决方案存在。任何低于我们检查sqrt(N)
的因子都会有相应的因子大于sqrt(N)
。所以我们只需要检查sqrt(N)
,然后我们就可以得到剩余的因素。
在这里,您不需要明确使用任何素数查找算法。分解逻辑本身将推断目标是否为素数。所以剩下的就是检查成对因素。
unsigned long long ans ;
for(unsigned long long i = 2; i<=target/i; i++)
while(target % i == 0){
ans = i;
target/=i;
}
if( target > 1 ) ans = target; // that means target is a prime.
//print ans
编辑:在早期代码中添加( chux ) - i*i
的点可能会导致溢出,如果我们使用i<=target/i
可以避免
另一个选择是
unsigned long long sqaure_root = isqrt(target);
for(unsigned long long i = 2; i<=square_root; i++){
...
}
这里注意,使用sqrt
不是明智的选择,因为 -
将双数学与整数运算混合容易产生舍入误差。
对于目标,答案为6857
。
答案 1 :(得分:4)
这是一个提示:给定一个任意整数值x
,如果我们发现y
是一个因素,那么我们已经隐含地发现x / y
也是一个因素。换句话说,因素总是成对出现。因此,在我们进行冗余工作之前,我们需要多长时间才能进行迭代。
那是什么限制?那么,y
大于x / y
的交叉点是什么?
一旦将此优化应用于外部循环,您将发现代码的运行时将受is_prime
函数的限制。但是,当然,你也可以采用类似的技术。
答案 2 :(得分:2)
代码有两个主要问题
while (i < target)
循环非常低效。找到因素后,target
可以缩减为target = target / i;
。此外,因子i
可能会多次出现。修复未显示。
is_prime(n)
效率非常低。其while (num > z && z !=num)
可以循环n
次。在这里,使用商来将迭代限制为sqrt(n)
次。
int is_prime (unsigned long long int num) {
unsigned long long int z = 2;
while (z <= num/z) {
if ((num % z) == 0) return 0;
z++;
}
return num > 1;
}
答案 3 :(得分:0)
is_prime
有鸡与蛋的问题,因为你只需要针对其他素数测试num
。因此,您不需要检查9,因为这是3的倍数。
is_prime
可以维护一个素数数组,每次测试一个新的num
是一个pime,它就可以添加到数组中。 num
isr针对数组中的每个素数进行测试,如果它不能被数组中的任何素数分割,它本身就是素数并被添加到数组中。 aray需要malloc'd和relloc'd,除非有一个formue来计算你的目标中的素数(我相信这样的公式不存在)。
编辑:测试目标600,851,475,143的素数将约为7,500,000,000,表格可能会耗尽内存。
该方法可以如下调整:
使用unsiged int
直至UINT_max
将unsigned long long int
用于
使用超过某种内存消耗的蛮力。
UINT_MAX
被定义为4,294,967,295,涵盖了大约100,000,000,000的素数,并且需要花费7.5 * 4 = 30Gb
答案 4 :(得分:0)
没有错,只需要优化,例如:
)
另外一个很大的问题是while(z&lt; num)但是因为你不想要解决方案我让你找到如何优化它,同样自己看第一个函数。
编辑:其他人在我之前50秒发布了素数列表的素数解决方案,这是最好的,但我选择提供一个简单的解决方案,因为你只是一个初学者和操纵数组可能起初并不容易(需要学习指针和东西)。