我一直在尝试解决欧拉计划中的问题,并注意到其中一些问题要求你确定一个质数。
我知道可以将x除以2、3、4、5,......直到x的平方根,如果得到平方根,就可以(安全地)假设该数字是质数。不幸的是,这个解决方案似乎相当笨重。
我已经研究了更好的算法来确定一个数是否为质数,但很快就被搞糊涂了。
有没有简单的算法可以确定X是否为质数,而不会让普通程序员感到困惑?
非常感谢!
我一直在尝试解决欧拉计划中的问题,并注意到其中一些问题要求你确定一个质数。
我知道可以将x除以2、3、4、5,......直到x的平方根,如果得到平方根,就可以(安全地)假设该数字是质数。不幸的是,这个解决方案似乎相当笨重。
我已经研究了更好的算法来确定一个数是否为质数,但很快就被搞糊涂了。
有没有简单的算法可以确定X是否为质数,而不会让普通程序员感到困惑?
非常感谢!
第一个算法非常好,经常在Project Euler中使用。如果您知道所需的最大数值,还可以研究埃拉托色尼筛法。
如果您维护质数列表,也可以改进第一个算法,只需用质数除直到该数的平方根为止。
有了这两个算法(除法和筛法),您应该能够解决问题。
编辑:如评论中所述更正了名字。
要生成小于某一限制值的所有质数,使用埃拉托色尼筛选法(该页面包含20种编程语言的变体)是最古老和最简单的解决方案。
在Python中:
def iprimes_upto(limit):
is_prime = [True] * limit
for n in range(2, limit):
if is_prime[n]:
yield n
for i in range(n*n, limit, n): # start at ``n`` squared
is_prime[i] = False
示例:
>>> list(iprimes_upto(15))
[2, 3, 5, 7, 11, 13]
yield
确实很令人困惑。 - Koray Tugay我看到Fermat素性检验已经被提出,但我一直在学习《计算机程序的构造和解释》,他们还提供了Miller-Rabin测试(见第1.2.6节,问题1.28)作为另一种选择。我已经成功地用它来解决欧拉计划的问题。
记住以下事实 (来自 MathsChallenge.net):
这是我用于相对较小的n的C++函数:
bool isPrime(unsigned long n)
{
if (n == 1) return false; // 1 is not prime
if (n < 4) return true; // 2 and 3 are both prime
if ((n % 2) == 0) return false; // exclude even numbers
if (n < 9) return true; //we have already excluded 4, 6, and 8.
if ((n % 3) == 0) return false; // exclude remaining multiples of 3
unsigned long r = floor( sqrt(n) );
unsigned long f = 5;
while (f <= r)
{
if ((n % f) == 0) return false;
if ((n % (f + 2)) == 0) return false;
f = f + 6;
}
return true; // (in all other cases)
}
这里有一个简单的优化方法,虽然不是埃拉托斯特尼筛法,但非常易于实现:首先尝试将X除以2和3,然后循环j = 1..sqrt(X)/ 6,尝试将其除以6 * j-1和6 * j +1。这自动跳过了所有可被2或3整除的数字,使您获得了相当不错的加速效果。
我建议使用费马素性测试。它是一种概率性测试,但通常情况下都是正确的。而且与筛法相比,速度非常快。
我也在解决欧拉计划问题,实际上刚刚完成了编号为#3的问题,即查找复合数的最高质因数(?中的数字是600851475143)。
我查看了所有关于质数的信息(这里已经提到的筛法技术),以及维基百科上的整数分解,并想出了一个暴力试除算法,我认为这个算法可以做到。
因此,当我通过欧拉问题学习Ruby时,我正在研究编写我的算法,并偶然发现了mathn库,其中包含Prime类和Integer类的prime_division方法。 多酷啊。 我使用以下Ruby代码片段得到了正确的问题答案:
require "mathn.rb"
puts 600851475143.prime_division.last.first
这段代码将正确的答案输出到控制台。当然,在我发现这个小技巧之前,我做了很多阅读和学习,我想与大家分享一下...
你说得对,最简单的方法是最慢的。你可以进行一些优化。
尝试使用模数代替平方根。 跟踪你的质数。你只需要将7除以2、3和5,因为6是2和3的倍数,4是2的倍数。
Rslite提到了eranthenos筛法。它相当直接。我在家里有几种语言的代码。如果你想让我稍后发布这个代码,请添加评论。
// Author: James J. Carman
// Project: Sieve of Eratosthenes
// Description: I take an array of 2 ... max values. Instead of removeing the non prime numbers,
// I mark them as 0, and ignoring them.
// More info: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
#include <iostream>
int main(void) {
// using unsigned short.
// maximum value is around 65000
const unsigned short max = 50000;
unsigned short x[max];
for(unsigned short i = 0; i < max; i++)
x[i] = i + 2;
for(unsigned short outer = 0; outer < max; outer++) {
if( x[outer] == 0)
continue;
unsigned short item = x[outer];
for(unsigned short multiplier = 2; (multiplier * item) < x[max - 1]; multiplier++) {
unsigned int searchvalue = item * multiplier;
unsigned int maxValue = max + 1;
for( unsigned short maxIndex = max - 1; maxIndex > 0; maxIndex--) {
if(x[maxIndex] != 0) {
maxValue = x[maxIndex];
break;
}
}
for(unsigned short searchindex = multiplier; searchindex < max; searchindex++) {
if( searchvalue > maxValue )
break;
if( x[searchindex] == searchvalue ) {
x[searchindex] = 0;
break;
}
}
}
}
for(unsigned short printindex = 0; printindex < max; printindex++) {
if(x[printindex] != 0)
std::cout << x[printindex] << "\t";
}
return 0;
}
我会尽快找到它,然后分享我拥有的Perl和Python代码。它们风格相似,只是行数较少。