C素因子分解(循环失败?)

时间:2015-06-01 17:35:26

标签: c for-loop

我现在一直在研究这段简单的代码1.5小时,但没有发现错误。我开始疯了;)

你们这些有着清新头脑和观点的人能给我一点暗示,我可能会犯错吗? (我对C来说比较新)

问题是:代码适用于我输入和测试的大多数数字,但我偶然发现了一个不起作用的数字:3486118(或55777888,它是它的倍数)它适用于第一个循环(s),但在因素2之后,它变成了无限循环。

这是我的代码:(非常感谢任何帮助)

// Program calculates prime factors of entered number and returns them

#include <stdio.h>

int main() {

    long int num, num_cp;
    long int product=1;

    /*prime number array up to 100.000*/
    long int prime[] = {2, 3, **[...cut out MANY numbers...]** 99971, 99989, 99991};

    printf("Please enter a positive integer:\n");
    scanf("%li", &num);//55777888 or 3486118 not working... why?
    //copy the entered number to keep the original for comparison with "product" and "break;" if equal
    num_cp=num;

    printf("prime factorization of %li:\n\n", num);

    for (int i=0; i<sizeof(prime); i++) {
        if (num_cp%prime[i]==0) {
            num_cp/=prime[i];
            product*=prime[i];
            if (product==num) {
                printf("%li\n\n", prime[i]);
                break;
            }
            printf("%li*", prime[i]);

            //If prime factor found but "product" is still not equal to "num" reset loop counter "i" to -1 (==0 in next loop)
            i=-1;
        }
    }
    printf("END");
    return 0;
}

2 个答案:

答案 0 :(得分:5)

“我现在一直在研究这段简单的代码1.5小时,但没有发现错误。我开始发疯了;)”

别。别管它。走开去吃披萨。在你最喜欢的电影面前出来。洗个澡。瞄准2048年(或其他)的新高分。你的大脑卡在车辙中,你不再看到你的代码了。你只看到你认为你的代码是什么。

当你的大脑离开车辙时,那么 - 只有这样 - 回去并实际阅读你写的代码。不是您认为编写的代码,而是您实际编写的代码。是的,他们是不同的。

答案 1 :(得分:1)

55777888的主要因素是2·2·2·2·2·1743059,其中最后一个因素太大而无法包含在您的列表中。

您可以在代码中修复此问题:当产品等于您找到的素数因子的乘积时,num_cp为1.如果num_cp大于1后用尽了主要列表,它是num的因子。如果num/num_cp小于您检查过的最大素数,则可以假设num_cp的剩余值为素数。如果不是,你早先发现了更多的因素。

您可以通过在主循环后添加额外的检查来解决此问题:

if (num_cp > 1) printf("%li\n\n", num_cp);

(如果long int是您系统上的64位数字,那么您仍然不安全:其余因素可能由数组中不存在的多个数字组成。)

最后:重置for循环计数器以使循环重新开始并不是一个好主意。它始终从头开始并重新检查您已检查的素数。它只是不自然的程序流程,这使得它很难阅读。在我看来,while循环而不是内部if块会更自然。

修改:举例说明:

#include <stdio.h>

int main() {
    long int num;

    /* prime number array up to 100.000 */
    long int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
    int nprime = sizeof(prime) / sizeof(*prime);

    num = 55;

    printf("%li == ", num);

    for (int i = 0; i < nprime; i++) {
        long int p = prime[i];

        if (num <= 1) break;

        while (num % p == 0) {
            num /= prime[i];
            printf("%li", p);
            if (num > 1) printf(" * ");
        }
    }

    if (num > 1) printf("%li", num);
    printf("\n");

    return 0;
}

注意事项:

  • 使用i循环而不是重置主循环计数器while,这会消耗相同因子的所有重复。如果素数p没有除数,则不会输入while循环,就像if子句一样。
  • 我删除了num的副本,并在整个过程中使用了num,主要是为了消除混乱。我还删除了product。你所有主要因素应该乘以原始数字的逻辑是好的。但它也是相反的:在将数字除以所有素数之后,我们留下1.我们必须将数字除以。通过删除产品,我们只需跟踪一个变量而不是两个变量。
  • 我已将break条件移至前方,因此我们会及时收到负数和0。

那就是说,你的代码方式并没有错,只是在某些地方可能有点不寻常。