我一直试图通过Project Euler工作,并注意到一些问题要求你确定一个素数作为其中的一部分。
我知道我可以将x除以2,3,4,5,...,X的平方根,如果我到达平方根,我可以(安全地)假设数字为素数。不幸的是,这个解决方案看起来很笨拙。
我研究过如何确定一个数字是否为素数的更好的算法,但是很快就会混淆。
是否有一个简单的算法可以确定X是否为素数,而不是混淆一个凡人的程序员?
非常感谢!
答案 0 :(得分:28)
第一个算法非常好,并且在Project Euler上使用了很多。如果你知道你想要的最大数量,你也可以研究Eratosthenes的筛子。
如果你保留素数列表,你也可以优化第一个算法,只用素数除以数字的平方根。
有了这两个算法(划分和筛子),你应该能够解决问题。
修改:注释
中注明的固定名称答案 1 :(得分:19)
生成小于限制Sieve of Eratosthenes的所有素数(该页面包含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]
答案 2 :(得分:11)
我看到Fermat的素性测试已被建议,但我一直在研究Structure and Interpretation of Computer Programs,他们也给Miller-Rabin test(见第1.2.6节,问题1.28)作为另一种选择。我一直在使用它成功解决欧拉问题。
答案 3 :(得分:5)
这是一个简单的方法优化,它不是Eratosthenes的Sieve,但很容易实现:首先尝试将X除以2和3,然后循环j = 1..sqrt(X)/ 6,试图除以6 * j-1和6 * j + 1。这会自动跳过可被2或3整除的所有数字,从而获得非常好的常数因子加速度。
答案 4 :(得分:5)
请记住以下事实(来自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)
}
您可能会想到自己的更多优化。
答案 5 :(得分:3)
我建议Fermat's primality test。这是一个概率测试,但它经常出人意料地正确。与筛子相比,它的速度非常快。
答案 6 :(得分:2)
对于相当小的数字,高达sqrt(x)的x%n非常快速且易于编码。
简单改进:
仅测试2和奇数。
测试2,3和6 +或-1的倍数(除了2或3之外的所有素数都是6 +/- 1的倍数,所以你基本上只是跳过所有偶数和所有3的倍数
仅测试素数(需要计算或存储所有素数到sqrt(x))
您可以使用筛选方法快速生成所有素数列表,直到某个任意限制,但它往往会占用大量内存。您可以使用6个技巧的倍数将内存使用量降低到每个数字的1/3。
我写了一个简单的素数类(C#),它使用两个位域为6 + 1的倍数和6-1的倍数,然后做一个简单的查找...如果我测试的数字超出了界限筛子,然后它回落测试2,3和6 +/- 1的倍数。我发现生成一个大筛子实际上需要花费更多的时间,因为我已经解决了大部分的欧拉问题。至今。 KISS原则再次爆发!
我写了一个使用筛子来预先计算较小质数的素数类,然后依靠测试2,3和6 +/- 1的倍数用于筛子范围之外的那些。
答案 7 :(得分:1)
对于Project Euler,拥有素数列表非常重要。我建议维护一个用于解决每个问题的列表。
我认为你要找的是Sieve of Eratosthenes。
答案 8 :(得分:1)
你的权利简单是最慢的。你可以稍微优化一下。
研究使用模数而不是平方根。 跟踪你的素数。你需要将7除以2,3和5,因为6是2和3的倍数,4是2的倍数。
Rslite提到eranthenos sieve。这是相当直接的。我家里有几种语言。如果您希望我稍后发布该代码,请添加评论。
这是我的C ++版。它有很大的改进空间,但与动态语言版本相比速度很快。
// 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代码。它们的风格相似,只是线条较少。
答案 9 :(得分:1)
这是D(数字火星)中的一个简单的素性测试:
/**
* to compile:
* $ dmd -run prime_trial.d
* to optimize:
* $ dmd -O -inline -release prime_trial.d
*/
module prime_trial;
import std.conv : to;
import std.stdio : w = writeln;
/// Adapted from: http://www.devx.com/vb2themax/Tip/19051
bool
isprime(Integer)(in Integer number)
{
/* manually test 1, 2, 3 and multiples of 2 and 3 */
if (number == 2 || number == 3)
return true;
else if (number < 2 || number % 2 == 0 || number % 3 == 0)
return false;
/* we can now avoid to consider multiples
* of 2 and 3. This can be done really simply
* by starting at 5 and incrementing by 2 and 4
* alternatively, that is:
* 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, ...
* we don't need to go higher than the square root of the number */
for (Integer divisor = 5, increment = 2; divisor*divisor <= number;
divisor += increment, increment = 6 - increment)
if (number % divisor == 0)
return false;
return true; // if we get here, the number is prime
}
/// print all prime numbers less then a given limit
void main(char[][] args)
{
const limit = (args.length == 2) ? to!(uint)(args[1]) : 100;
for (uint i = 0; i < limit; ++i)
if (isprime(i))
w(i);
}
答案 10 :(得分:1)
我正在通过Project Euler问题工作,事实上刚刚完成#3(通过id),这是搜索复合数字的最高素数因子(?中的数字是600851475143)。
我查看了关于素数的所有信息(这里已经提到的筛选技术),以及维基百科上的整数因子分解,并提出了我认为可以做的蛮力试验分割算法。
因此,当我正在研究euler问题以学习ruby时,我正在研究编码我的算法并偶然发现了具有Prime class和Integer class with a prime_division方法的mathn库。多么酷啊。我能够通过这个ruby片段得到问题的正确答案:
require "mathn.rb"
puts 600851475143.prime_division.last.first
此代码段会向控制台输出正确的答案。当然,在我偶然发现这个小小的美女之前,我最终做了大量的阅读和学习,我以为我会和大家分享......
答案 11 :(得分:0)
我喜欢这个python代码。
def primes(limit) :
limit += 1
x = range(limit)
for i in xrange(2,limit) :
if x[i] == i:
x[i] = 1
for j in xrange(i*i, limit, i) :
x[j] = i
return [j for j in xrange(2, limit) if x[j] == 1]
此变体可用于生成数字因子。
def factors(limit) :
limit += 1
x = range(limit)
for i in xrange(2,limit) :
if x[i] == i:
x[i] = 1
for j in xrange(i*i, limit, i) :
x[j] = i
result = []
y = limit-1
while x[y] != 1 :
divisor = x[y]
result.append(divisor)
y /= divisor
result.append(y)
return result
当然,如果我考虑一批数字,我就不会重新计算缓存;我会做一次并在其中进行查找。
答案 12 :(得分:0)
没有优化,但它是一个非常简单的功能。
function isprime(number){
if (number == 1)
return false;
var times = 0;
for (var i = 1; i <= number; i++){
if(number % i == 0){
times ++;
}
}
if (times > 2){
return false;
}
return true;
}
答案 13 :(得分:0)
也许Java的这种实现可能会有所帮助:
public class SieveOfEratosthenes {
/**
* Calling this method with argument 7 will return: true true false false true false true false
* which must be interpreted as : 0 is NOT prime, 1 is NOT prime, 2 IS prime, 3 IS prime, 4 is NOT prime
* 5 is prime, 6 is NOT prime, 7 is prime.
* Caller may either revert the array for easier reading, count the number of primes or extract the prime values
* by looping.
* @param upTo Find prime numbers up to this value. Must be a positive integer.
* @return a boolean array where index represents the integer value and value at index returns
* if the number is NOT prime or not.
*/
public static boolean[] isIndexNotPrime(int upTo) {
if (upTo < 2) {
return new boolean[0];
}
// 0-index array, upper limit must be upTo + 1
final boolean[] isIndexNotPrime = new boolean[upTo + 1];
isIndexNotPrime[0] = true; // 0 is not a prime number.
isIndexNotPrime[1] = true; // 1 is not a prime number.
// Find all non primes starting from 2 by finding 2 * 2, 2 * 3, 2 * 4 until 2 * multiplier > isIndexNotPrime.len
// Find next by 3 * 3 (since 2 * 3 was found before), 3 * 4, 3 * 5 until 3 * multiplier > isIndexNotPrime.len
// Move to 4, since isIndexNotPrime[4] is already True (not prime) no need to loop..
// Move to 5, 5 * 5, (2 * 5 and 3 * 5 was already set to True..) until 5 * multiplier > isIndexNotPrime.len
// Repeat process until i * i > isIndexNotPrime.len.
// Assume we are looking up to 100. Break once you reach 11 since 11 * 11 == 121 and we are not interested in
// primes above 121..
for (int i = 2; i < isIndexNotPrime.length; i++) {
if (i * i >= isIndexNotPrime.length) {
break;
}
if (isIndexNotPrime[i]) {
continue;
}
int multiplier = i;
while (i * multiplier < isIndexNotPrime.length) {
isIndexNotPrime[i * multiplier] = true;
multiplier++;
}
}
return isIndexNotPrime;
}
public static void main(String[] args) {
final boolean[] indexNotPrime = SieveOfEratosthenes.isIndexNotPrime(7);
assert !indexNotPrime[2]; // Not (not prime)
assert !indexNotPrime[3]; // Not (not prime)
assert indexNotPrime[4]; // (not prime)
assert !indexNotPrime[5]; // Not (not prime)
assert indexNotPrime[6]; // (not prime)
assert !indexNotPrime[7]; // Not (not prime)
}
}
答案 14 :(得分:-1)
AKS主要测试算法:
Input: Integer n > 1
if (n is has the form ab with b > 1) then output COMPOSITE
r := 2
while (r < n) {
if (gcd(n,r) is not 1) then output COMPOSITE
if (r is prime greater than 2) then {
let q be the largest factor of r-1
if (q > 4sqrt(r)log n) and (n(r-1)/q is not 1 (mod r)) then break
}
r := r+1
}
for a = 1 to 2sqrt(r)log n {
if ( (x-a)n is not (xn-a) (mod xr-1,n) ) then output COMPOSITE
}
output PRIME;
答案 15 :(得分:-2)
python中的另一种方式是:
import math
def main():
count = 1
while True:
isprime = True
for x in range(2, int(math.sqrt(count) + 1)):
if count % x == 0:
isprime = False
break
if isprime:
print count
count += 2
if __name__ == '__main__':
main()