【问题标题】:program compiles but does not executes程序编译但不执行
【发布时间】:2016-09-30 18:35:47
【问题描述】:

我编译了程序,但是当我输入=600851475143时没有结果。程序是找到最大的素数(13195的素数是5、7、13和29。最大的素数是多少?号码 600851475143?) 怎么了?

#include<stdio.h>


int isprime(unsigned long  n){
    unsigned long i;
    for(i=2;i<n;i++){
        if((n%i)==0){
            return 0;
        }
    }
    return 1;
}

int main(){
    unsigned long n,i,lpf;
    scanf("%ld",&n);
    for(i=2;i<n;i++){
        if(n%i==0){
            if(isprime(i)==1){
            lpf=i;}
        }
    }
    printf("%ld",lpf);
    return 0;
}

【问题讨论】:

  • 对于大数字,计算需要相当长的时间,而且%ld 不是unsigned long 的正确说明符。
  • 您的 unsigned long 需要是 64 位的。是吗?正如其他人所说,计算的数量简直是巨大的,所以程序可能会运行 。您需要一种更聪明的方法来解决问题。我的 pennyworth 是因为你想找到 最大 素数,所以从上到下而不是自下而上工作。哦,不要检查偶数或除数。

标签: c


【解决方案1】:

你有一个 for 循环,它运行的次数大约是你输入的数字,i2n-1。在那个 for 循环中,您调用一个函数,该函数大致运行 i 次,这与循环中的 i 相同。这意味着您的程序围绕n^2 进行数学计算,其中n 是您的输入。如果输入一个 12 位数字,n^2 是 24 位数字的大小,对于一个程序来说,做一个 10^24 的计算会花费很多时间。所以你的程序确实运行,它只是计算。

【讨论】:

    【解决方案2】:

    早些时候,我注意到我原来的解决方案:

    600851475143 仍然需要很长时间,所以是时候寻找一个 完全不同的算法

    搜索 SO 出现 efficient ways of finding the largest prime factor of a number

    这是一个基于@under5hell 在该页面上的回答的简单快速的解决方案:

    #include <stdio.h>
    #include <assert.h>
    
    int main()
    {
        unsigned long long number;
    
        assert(sizeof(number) * 8 >= 64); // make sure we've enough bits
    
        scanf("%llu", &number);
    
        for (unsigned long long divisor = 2; divisor < number; divisor++) {
            if (number % divisor == 0) {
                number /= divisor--; // decrement to remove multiples
            }
        }
    
        printf("%llu\n", number);
    
        return 0;
    }
    

    哪一个能在几分之一秒内找到 600851475143 的最大素数:

    输出

    > ./a.out
    600851475143
    6857
    > 
    

    故事的寓意似乎是在查询 SO 之前先搜索 SO!

    【讨论】:

    • 600851475143 需要 41 位。 unsigned long类型只需提供32;从 C99 开始,C 提供了[unsigned] long long,它可以保存这个值。
    • 是的,@Kaz,当我看到你的评论时,我正在处理这个问题。尽管我确定我确实应该使用 uint64_t 或类似的东西,但我已经将它提高了很长时间并做出了 64 位断言。
    【解决方案3】:

    正如其他人已经说过的:你不需要走完整的路。上到n的平方根就足够了,你也可以在每次找到一个因数的时候减少n本身的值。

    一种稍微快一点的方法是使用轮子,尽管时间复杂度与原始版本相同。这里使用的轮子是 11 个粗略数字之间的距离(加上之前的素数和下一轮的偏移量)。

    大家一起:

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define ISPRIME(x) isprime(x)
    //#define ISPRIME(x) isprime_wheel(x)
    
    static int wheel[] = {
    1, 2, 2, 4, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2,
    4, 2, 4, 14, 4, 6, 2, 10, 2, 6, 6, 4, 2, 4, 6, 2, 10, 2, 4, 2, 12, 10, 2, 4, 2,
    4, 6, 2, 6, 4, 6, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 6, 8, 6, 10, 2, 4, 6,
    2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 6, 10, 2, 10, 2, 4, 2, 4, 6, 8, 4, 2, 4, 12,
    2, 6, 4, 2, 6, 4, 6, 12, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 10, 2, 4, 6, 2,
    6, 4, 2, 4, 2, 10, 2, 10, 2, 4, 6, 6, 2, 6, 6, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8,
    4, 2, 6, 4, 8, 6, 4, 6, 2, 4, 6, 8, 6, 4, 2, 10, 2, 6, 4, 2, 4, 2, 10, 2, 10,
    2, 4, 2, 4, 8, 6, 4, 2, 4, 6, 6, 2, 6, 4, 8, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4,
    6, 6, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2, 10, 2, 10, 2, 6, 4, 6, 2, 6, 4,
    2, 4, 6, 6, 8, 4, 2, 6, 10, 8, 4, 2, 4, 2, 4, 8, 10, 6, 2, 4, 8, 6, 6, 4, 2, 4,
    6, 2, 6, 4, 6, 2, 10, 2, 10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 6, 6, 4,
    6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 8, 4, 6, 2, 6, 6, 4, 2, 4, 6, 8, 4, 2, 4, 2, 10,
    2, 10, 2, 4, 2, 4, 6, 2, 10, 2, 4, 6, 8, 6, 4, 2, 6, 4, 6, 8, 4, 6, 2, 4, 8, 6,
    4, 6, 2, 4, 6, 2, 6, 6, 4, 6, 6, 2, 6, 6, 4, 2, 10, 2, 10, 2, 4, 2, 4, 6, 2, 6,
    4, 2, 10, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2, 12, 6, 4, 6, 2, 4, 6, 2, 12,
    4, 2, 4, 8, 6, 4, 2, 4, 2, 10, 2, 10, 6, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4,
    2, 10, 6, 8, 6, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 6, 6, 4, 6, 2, 6, 4, 2, 4,
    2, 10, 12, 2, 4, 2, 10, 2, 6, 4, 2, 4, 6, 6, 2, 10, 2, 6, 4, 14, 4, 2, 4, 2, 4,
    8, 6, 4, 6, 2, 4, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 12, 2, 12
    };
    
    int isprime_wheel(unsigned long n)
    {
      unsigned long isqrt = (unsigned long) (floor(sqrt(n)) + 1);
      unsigned long start = 5, factor = 2;
      int wlen = sizeof(wheel) / sizeof(int);
      int next = 0;
      if(n == 2){
        return 1;
      }
      if ((n & 1) == 0) {
        return 0;
      }
      if (isqrt * isqrt == n) {
        return 0;
      }
      while (factor < isqrt) {
        if (n % factor == 0) {
          return 0;
        }
        factor += (unsigned long) wheel[next];
        next++;
        if (next == wlen) {
          next = start;
        }
      }
    
      return 1;
    }
    
    unsigned long primefactors(unsigned long n)
    {
      unsigned long start = 5, factor = 2;
      unsigned long biggest = 0;
      int wlen = sizeof(wheel) / sizeof(int);
      int next = 0;
      if (n == 1) {
        return 0;
      }
      if (n == 2 || n == 3) {
        return n;
      }
    
      while (factor <= n) {
        while (n % factor == 0) {
          biggest = factor;
          n /= factor;
        }
        factor += (unsigned long) wheel[next];
        next++;
        if (next == wlen) {
          next = start;
        }
      }
      if (n > 1 && biggest == 0) {
        return n;
      }
    
      return biggest;
    }
    
    
    
    int isprime(unsigned long n)
    {
      unsigned long i;
      unsigned long isqrt = (unsigned long) floor(sqrt(n)) + 1;
    
      for (i = 2; i < isqrt; i++) {
        if ((n % i) == 0) {
          return 0;
        }
      }
      return 1;
    }
    
    #include <time.h>
    int main()
    {
      unsigned long n, i, lpf = 0, wheelfactor = 0;
      clock_t start,stop;
    
      if(scanf("%lu", &n) != 1){
         fprintf(stderr,"Must be a positive, small integer \n");
         exit(EXIT_FAILURE);
      }
    
      start = clock();
      wheelfactor = primefactors(n);
      stop = clock();
      printf("WHEEL Time %.10f seconds\n", (double) (stop - start) / CLOCKS_PER_SEC);
      printf("WHEEL %lu\n",wheelfactor );
    
      start = clock();
      if (n == 1) {
        puts("0");
        goto END;
      }
      if (n == 2 || ISPRIME(n) == 1) {
        printf("NAIVE %lu (n is prime, next print must show 0)\n", n);
        goto END;
      }
      for (i = 2; i < n / 2 + 1; i++) {
        if (ISPRIME(i) == 1 && n % i == 0) {
          //printf("PRIME %lu\n", i);
          lpf = i;
          n /= i;
          // n might be down to 2 and isprime(2) returns true
          // but  only odd primes are allowed at this point
          if (ISPRIME(n) == 1 && n > lpf) {
            //printf("ISPRIME %lu\n", n);
            lpf = n;
          }
        }
      }
    END:
      stop = clock();
    
      printf("NAIVE Time %.10f seconds\n", (double) (stop - start) / CLOCKS_PER_SEC);
      printf("NAIVE %lu\n", lpf);
      return 0;
    }
    

    您可以尝试使用一些大型复合材料,例如:11529215046068460 以查看运行时的差异,或者 1152921123 这有点极端,需要很大的耐心——可能需要几分钟。

    【讨论】:

    • @cdlane yepp,我的错,外循环必须是 n/2 +1 当然,我们在这里搜索因子而不是素数,如果其中一个因子是 2 ...
    • @cdlane 素数没有素因数。如果需要,只需在进入外循环之前首先检查它是否是素数。但是我添加它是没有问题的。
    • 您能否提供一个网站链接,该网站解释说“素数没有素数”,因为我不断遇到诸如“所有整数 n > 1 都有素数”和“当 n 是素数,素数分解就是 n 本身”。
    • @cdlane 发现更多错误,希望我能全部修复,请检查
    • @cdlane 添加了一个带轮子的算法,在执行此操作时,我发现我的 JavaScript 实现中的轮子似乎已损坏(很简单,一个 C&P 错误),它给出了错误的结果。有时。所以感谢你让我修复了我已发布的程序中的一个错误!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 2023-01-11
    • 1970-01-01
    相关资源
    最近更新 更多