我有一个循环,从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 ;
}
答案 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是文件中的最后一个素数。