简体   繁体   English

C素数分解(循环失败?)

[英]C prime factorization (loop failure?)

I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. 我一直在研究这段简单的代码1.5个小时,但没有发现错误。 I start going crazy ;) 我开始疯了;)

Could anyone of you with a fresh mind and view give me a little hint, where I might have the mistake in? 你们每个人只要有新的想法和观点,都可以给我一点提示,我可能在哪里出现错误? (I am relatively new to C) (我是C的新手)

The problem is: The code works fine for most of the numbers I entered and tested, but accidentically I found a number that does not work: 3486118 (or 55777888 which is a multiple of it) It goes right for the first loop(s), but after factor 2 it becomes an endless loop. 问题是:该代码对于我输入并测试的大多数数字都可以正常工作,但是偶然地我发现了一个不起作用的数字:3486118(或55777888的整数倍),它适合于第一个循环,但是在因子2之后,它将变成一个无限循环。

Here is my code: (any help is greatly appreciated) 这是我的代码:(非常感谢您的帮助)

// 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;
}

"I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)" “我一直在研究这段简单的代码1.5个小时,但没有发现错误。我开始发疯了;)”

Don't. 别。 Leave it. 别管它。 Go away and eat a pizza. 走开,吃披萨。 Veg out in front of your favourite movie. 在您最喜欢的电影前播放视频。 Have a shower. 洗个澡。 Aim for a new high-score on 2048 (or whatever). 力争在2048(或更高水平)上取得新的高分。 Your brain gets stuck in a rut and you are no longer seeing your code. 您的大脑陷入了车辙,您再也看不到代码了。 You are only seeing what you think your code is. 您只会看到您认为的代码。

When you get your brain out of the rut, then -- and only then -- go back and actually read the code you wrote. 当您精疲力尽时,然后-仅在此之后-返回并实际阅读您编写的代码。 Not the code you think you wrote, but the code you actually wrote. 不是您认为自己编写的代码,而是您实际编写的代码。 Yes, they are different. 是的,它们是不同的。

The prime factors of 55777888 are 2·2·2·2·2·1743059, where the last factor is too large to be contained in your list. 55777888的主要因子是2·2·2·2·2·1743059,其中最后一个因子太大而无法包含在列表中。

You can fix this in your code: When the product is equal to the product of the prime factors you have found, num_cp is 1. If num_cp is greater than one after you have exhausted your prime list, it is a factor of num . 您可以在代码中解决此问题:当乘积等于找到的素数乘积时, num_cp为1。如果在用完素数列表后num_cp大于1,则为num If num/num_cp is smaller than the largest prime you have checked, you can assume that the remaining value of num_cp is a prime. 如果num/num_cp小于您检查的最大素数,则可以假定num_cp的剩余值为素数。 If it wasn't you'd have found more factors earlier. 如果不是,那么您会更早发现更多因素。

You can fix this by adding an additional check after your main loop: 您可以通过在主循环后添加其他检查来解决此问题:

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

(If long int is a 64-bit number on your system, you're still not safe: The remaining factor might be made up of several numbers that are not in your array.) (如果long int是系统上的64位数字,则您仍然不安全:剩余因素可能由数组中没有的几个数字组成。)

Finally: Resetting the for loop counter so that the loop starts over isn't a good idea. 最后:重置for循环计数器以使循环重新开始不是一个好主意。 It always starts from the beginning and re-checks primes that you have already checked. 它总是从头开始,并重新检查您已经检查过的素数。 And it just isn't natural program flow, which makes it hard to read. 而且这不是自然的程序流程,这使得它很难阅读。 A while loop instead of the inner if block would be more natural in my opinion. 我认为,使用while循环而不是内部if块会更自然。

Edit : To illustrate: 编辑 :以说明:

#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;
}

Things to note: 注意事项:

  • Instead of resetting the main loop counter i , a while loop is used, which consumes all repetitions of the same factor. 不用重置主循环计数器i ,而是使用while循环,它消耗了相同因子的所有重复。 If a prime p doesn't divide the number, the while loop isn't entered, just like an if clause. 如果素数p不除数,则不输入while循环,就像if子句一样。
  • I've removed the copy of num and used num throughout, mainly to remove clutter. 我删除了num的副本并在整个过程中使用了num ,主要是为了消除混乱。 I've also removed the product . 我还删除了该product Your logic that all prime factors should multiply to the original number, is good. 所有素因应乘以原始数的逻辑是好的。 But it also works the other way round: After dividing the number by all primes, we are left with 1. And we have to divide the number anyways. 但这也反过来起作用:将数字除以所有质数后,剩下的就是1。无论如何,我们必须对数字进行除法。 By removing the product, we have to keep track of only one variable instead of two. 通过删除产品,我们必须仅跟踪一个变量,而不是两个变量。
  • I've moved the break condition to the front, so we catch negative numbers and 0 early. 我已将break条件移到最前面,因此我们早早发现了负数和0。

That said, your way to code isn't wrong, just maybe a bit unusual in places. 也就是说,您的编码方式没有错,在某些地方也许有点不寻常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM