【问题标题】:Infinite loop happening somewhere here?无限循环发生在这里的某个地方?
【发布时间】:2014-01-21 16:50:30
【问题描述】:

我正在编写一个程序来估计素数的非负整数的百分比。以下代码以某种方式产生了一个无限循环,因为我的输出在我正在使用的在线编译器上显示“超时”。但是,我无法弄清楚代码的哪一部分产生了问题。对我来说,它看起来很简单。

#include <iostream> 

bool isPrime(unsigned long L) { 
    if (L < 3) { 
        return true; 
    } else { 
        unsigned long i = 2;
        while (i < L)
           if (L % i++ == 0)
                return false;
    }
    return true;
}

int main() { 

    unsigned long k = 0;
    unsigned long N = ~k;
    unsigned long count = 0;
    while (k++ < N)  
        if (isPrime(k)) 
            ++count;

    long double percentPrime = count / N;
    std::cout << "Percentage of prime numbers from 0 to " << N << " = " << percentPrime;

    return 0;
} 

【问题讨论】:

  • 或者运行很慢...
  • if (L &lt; 3) return true; – 这是对“素数”一词的相当大胆的重新定义,你知道……
  • 没有无限循环。只有一个非常long 一个。
  • 请注意,即使您的计算以某种方式运行了足够长的时间以完成,count / N; 会导致0,因为它执行整数除法。这是一个调试周期。
  • 那么0非负整数中素数的百分比(也就是说,它是M趋于无穷大的比例的极限小于 M 且为素数的非负整数)。所以只要摆脱循环,你就完成了;-)

标签: c++ loops infinite-loop primes


【解决方案1】:

首先,您的循环不是无限的。它会一直运行,直到到达0xFFFFFFFF,这将需要很长时间。

它将永远花费的部分原因是您正在使用相当于O(N^2) 算法(因此需要0xFFFFFFFF * 0xFFFFFFFF 操作才能完成)。

您应该使用筛子,或者至少优化您的is_prime 函数:

bool is_prime(unsigned int i, const std::deque<unsigned int>& previous_primes)
{
    std::size_t j = 0;
    while (previous_primes[j] * previous_primes[j] <= i)
    {
        if (i % previous_primes[j] == 0)
            return false;
        ++j;
    }
    return true;
}

然后您的主要代码将是:

// initialize some known primes
std::deque<unsigned int> primes;
primes.push_back(2);
primes.push_back(3);
primes.push_back(5);
primes.push_back(7);

for (unsigned int i = 9; i <= 0xFFFFFFFF; i += 2)
{
    if (is_prime(i, primes))
    {
        primes.push_back(i);
    }
}

// your percentage of primes would be (mathematically) primes.size() / 0xFFFFFFFF

请注意,由于迭代,这将仍然永远循环遍历从 9 到 0xFFFFFFFF 的所有奇数。

旁注

实际上,您正在编写一个程序来显示以下简单证明:

  • 从 2 开始,因此素数的百分比必须小于 0.5,因为其他数字都可以被 2 整除。
  • 接下来是 3,因此素数的百分比必须小于 0.33,因为每个第三个数都可以被 3 整除。
  • 下一个 5 ...

随着质数越来越大,最大百分比变为1/some infinite prime ~= 0。(f(x) = 1/x x 接近无穷大时的极限为 0。

所以在这里,数学证明比您尝试编程证明要快得多。

【讨论】:

    【解决方案2】:
    unsigned long k = 0;
    unsigned long N = ~k;
    

    这里的 N 将是 0xFFFFFFFF,这是一个非常大的数字,因此循环不是无限的,而是很长的。

    【讨论】:

    • 0xFFFFFFFFFFFFFFFF 在 64 位 Linux 系统上。
    • 对,我倾向于忘记 64 位的不同长度,因为我总是在我的代码中对它们进行 typedef。
    【解决方案3】:

    它似乎不是无限的,但由于它很长而且很耗时,所以它是超时的。

    我的建议是用一些技巧来改进你的素数测试:

    1 - 你只需要测试数字直到它的平方根 (sqrt(L))

    2 - 您只需要测试奇数的素数(因此您可以开始尝试将数字除以 3 并将测试增加 2,因此您将针对 3、5、7、9 等进行测试。 .)

    干杯

    【讨论】:

    • 3 - 您只需要针对之前发现的其他素数进行测试
    • @paul23 是的,我没有添加这个,因为您必须将其他素数存储在某个地方,而且大多数情况下这是不合理的。不过你是对的,谢谢提醒。
    • @prmottajr 如果您在一个序列中测试的不仅仅是几个素数,它肯定合理的。 :)
    【解决方案4】:

    不是无限的,只是非常长。

    如果你写的是while (k++ &lt;= N)而不是while (k++ &lt; N),那将是无限的......

    顺便说一句,1 通常不被认为是质数,但您的代码证明它是。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-28
    • 2015-12-24
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 2011-12-08
    相关资源
    最近更新 更多