C代码永远运行*

时间:2017-12-30 17:15:04

标签: c long-integer

我试图在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;
}

5 个答案:

答案 0 :(得分:4)

通过迭代直到数字的平方根,我们可以得到它的所有因素。(factorN/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)

任何事情的6000亿次迭代都需要一些非常重要的时间。你需要大幅降低这一点。

这是一个提示:给定一个任意整数值x,如果我们发现y是一个因素,那么我们已经隐含地发现x / y也是一个因素。换句话说,因素总是成对出现。因此,在我们进行冗余工作之前,我们需要多长时间才能进行迭代。

那是什么限制?那么,y大于x / y的交叉点是什么?

一旦将此优化应用于外部循环,您将发现代码的运行时将受is_prime函数的限制。但是,当然,你也可以采用类似的技术。

答案 2 :(得分:2)

代码有两个主要问题

  1. while (i < target)循环非常低效。找到因素后,target可以缩减为target = target / i;。此外,因子i可能会多次出现。修复未显示。

  2. 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

另见The Prime Pages

答案 4 :(得分:0)

没有错,只需要优化,例如:

)

另外一个很大的问题是while(z&lt; num)但是因为你不想要解决方案我让你找到如何优化它,同样自己看第一个函数。

编辑:其他人在我之前50秒发布了素数列表的素数解决方案,这是最好的,但我选择提供一个简单的解决方案,因为你只是一个初学者和操纵数组可能起初并不容易(需要学习指针和东西)。