找到Primes的有效方法

时间:2014-06-12 12:56:29

标签: c++ performance loops math

我有一个循环,从3到两个主要用户输入数字的phi(这些数字可以是任意长度),找到两者之间的所有素数,并将它们存储到一个数组中。

我的循环代码:

int coPrimes(int num)
{
    for (int i=3; i<=num; i++)
        if(isPrime(i))
            coprimes.push_back(i);

此循环需要很长时间才能完成。

Enter a prime number for 'a': 601
Enter a prime number for 'b': 769
a value: 601
b value: 769
product: 462169
phi: 460800
pubKey: 19
privKey: 145515

Process returned 0 (0x0)   execution time : **756.670 s**
Press any key to continue.

我需要这个循环以更快的速度工作。是否有更有效的方法来执行此操作?

P.S。我的循环调用另一个函数isPrime,如果有人想要它,这里是它的代码。

bool isPrime(int num)
{
    bool prime = true;

    if(num < 2)
        prime = true;
    for (int i=2; i<num; i++)
        if (num % i == 0)
            prime = false;
    return prime ;
}

5 个答案:

答案 0 :(得分:4)

他们看待你的问题的方法是,你想找到[a,b]范围内的所有素数。

如果你有足够的内存,最快的方法就是使用Sieve of Eratosthenes。维基百科有一个很好的演示如何运作:

2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
     

列表中的第一个数字是2;划掉每个第二个号码   之后的列表从2开始以2为增量进行计数(这些将是   是列表中2的倍数):

2  3  x  5  x  7  x  9   x 11  x 13  x 15  x 17  x 19  x 21  x 23  x 25
     

2后的列表中的下一个数字是3;每一个   列表中的第3个数字,以3为增量从3开始向上计数   3(这些将是列表中3的倍数):

2  3  x  5  x  7  x  x   x 11  x 13  x  x  x 17  x 19  x  x  x 23  x 25
     

3为5之后,列表中尚未划掉的下一个数字;通过从5开始以5为增量(即所有5的倍数)向上计数,将列表中的每第5个数字交叉出来:

2  3  x  5  x  7  x  x   x 11  x 13  x  x  x 17  x 19  x  x  x 23  x  x

这比检查每个数字是否为素数更快,因为外部循环仅在每个素数上运行,并且内部循环运行得越来越快。素数的倒数之和为loglogn,因此总共得到O(nloglogn)时间。比当前的O(n^2)O(n^(3/2))好得多,可以加快检查。

答案 1 :(得分:2)

您的案例中的性能下降来自您的素性测试程序。试试这个作为第一个优化:

bool isPrime(int num)
{
    bool prime = true;

    if(num < 2)
        prime = true;
    for (int i = 2; i < (int)sqrt(num) + 1; i++)
        if (num % i == 0)
            prime = false;
    return prime ;
}

您可以在此处找到一些基本素数测试的其他优化步骤:http://en.kioskea.net/faq/977-c-language-checking-whether-an-integer-is-a-prime-number

答案 2 :(得分:2)

我建议使用Eratosthenes的Sieve来解决你的问题。但我也看到了或多或少的三个非常简单的优化,可以加快你的代码!

for (int i=3; i<=num; i += 2)
    if(isPrime(i))
        coprimes.push_back(i);

这将跳过每个偶数。我们知道他们不是最重要的。你已经加倍了你的速度! (不太相似)。

以下是接下来的两个优化:

bool isPrime(int num)
{
    // If your function is only executed from that loop above, delete this statement.
    if(num < 2)
        return false;

    if(!(num % 2))
        return num == 2;

    int limit = sqrt(num);
    for (int i=3; i<=limit; i += 2)
        if (!(num % i))
            // You can stop after you found the first divisor
            return false;

    return true;
}

您不需要布尔值,因为除了最后一个return之外,您从未使用它。在那之后你应该首先检查它是否可以被2整除。如果是这样,我们可以结束。这允许再次跳过所有偶数除数。接下来取你编号的平方根来检查。我知道这是耗时的,但它需要更多的数字,因为你不必检查大部分数字。

通过这些小优化,您的代码将会快得多。我想它应该可以在不到100秒的时间内完成(如果你以前的结果超过700)。

答案 3 :(得分:1)

要搜索大量的素数,最好使用Eratosthenes和维基百科的筛子,这是一个好的开始。从那里我学会了这个算法。

答案 4 :(得分:0)

您似乎经常使用此程序,为什么不尝试实施Eratosthenes的筛子以及将结果存储在文件中?

这将带来的不仅仅是您在向量中添加素数,而是将结果写入文件。这样你可能只需要慢慢运行一次,将来你可以检查phi是否大于文件中的最后一个数字。如果不是,那么你可以使用文件中的数字。如果是,只需从n + 1开始检查到phi,其中n是文件中的最后一个素数。