我读了很多算法来查找素数,结论是如果数字不能被前面的任何素数整除,则数字是素数。
我无法找到更准确的定义。基于此,我编写了一个代码并且它表现令人满意,直到我传递的最大数量为1000000.但我相信有更快的算法可以找到比给定数字更小的所有素数。
以下是我的代码,我可以有更好的版本吗?
public static void main(String[] args) {
for (int i = 2; i < 100000; i++) {
if (checkMod(i)) {
primes.add(i);
}
}
}
private static boolean checkMod( int num) {
for (int i : primes){
if( num % i == 0){
return false;
}
}
return true;
}
答案 0 :(得分:19)
你的素性测试中的好处是你只能按素数划分。
private static boolean checkMod( int num) {
for (int i : primes){
if( num % i == 0){
return false;
}
}
return true;
}
糟糕的是,你除以到目前为止发现的所有素数,也就是说,所有素数都小于候选者。这意味着对于低于一百万的最大素数999983,你除以78497个素数以发现这个数字是素数。这是很多工作。事实上,在这个算法中花费在素数上的工作占了所有工作的大约99.9%,当达到一百万时,更大的部分用于更高的限制。并且该算法几乎是二次的,以这种方式找到n
的素数,你需要执行大约
n² / (2*(log n)²)
分裂。
一个简单的改进是提前停止分裂。假设n
是一个复合数(即一个数字大于1且除数为1且n
除数的除数),并且d
是n
的除数。
现在,d
是n
的除数意味着n/d
是一个整数,也是n
的除数:n/(n/d) = d
。
因此,我们可以自然地将n
的除数分组成对,每个除数d
生成(d, n/d)
对。
对于这样一对,有两种可能性:
d = n/d
,表示n = d²
或d = √n
。d < n/d
。但这会立即转换为d² < n
或d < √n
。因此,无论哪种方式,每对除数都包含(至少)不超过√n
的除数,因此,如果n
是复合数,则其最小除数(除1之外)不超过√n
。
因此,当我们到达√n
时,我们可以停止审判部门:
private static boolean checkMod( int num) {
for (int i : primes){
if (i*i > n){
// We have not found a divisor less than √n, so it's a prime
return true;
}
if( num % i == 0){
return false;
}
}
return true;
}
注意:这取决于按升序迭代的素数列表。如果语言无法保证,则必须使用不同的方法,通过ArrayList
或类似的方式按索引进行迭代。
在候选人的平方根处停止试验分区,对于100万以下的最大素数,999983,我们现在只需要将其除以1000以下的168个素数。这比以前少得多。在平方根处停止试验分区,并且只用素数除法,就像试验分区可能获得并且要求一样好
2*n^1.5 / (3*(log n)²)
对于n = 1000000
来说,这是一个大约750的因素,不错,是吗?
但这仍然不是很有效,找到n
以下所有素数的最有效方法是筛子。简单实现是经典的Sieve of Eratosthenes。在O(n * log log n)运算中找到n
以下的素数,并进行了一些增强(预先考虑了几个小素数的倍数),其复杂度可以简化为O(n)运算。一个具有更好渐近行为的相对较新的筛是Sieve of Atkin,它在O(n)运算中找到n
的素数,或者在O(n)中增强消除一些小素数的倍数。 / log log n)操作。
Atkin的筛选实施起来更加复杂,因此Eratosthenes筛选的良好实施可能比天然的Atve筛选实施得更好。对于类似优化级别的实现,性能差异很小,除非限制变大(大于10 10 ;并且在实践中,Eratosthenes的筛子比Atkin的筛子更好地扩展并不罕见那,由于更好的内存访问模式)。所以我建议从Eratosthenes筛选开始,只有在优化方面努力表现不尽如人意,才能深入研究阿特金筛选。或者,如果您不想自己实现它,请找一个其他人已经认真调整过的好实现。
我在an answer中进行了一些更详细的设置,设置略有不同,问题是找到了第n个素数。一些或多或少有效方法的实现与该答案相关联,特别是一个或两个可用的(虽然没有太多优化)Eratosthenes筛选的实现。
答案 1 :(得分:1)
我总是使用Eratosthenes筛子:
isPrime[100001] // - initially contains only '1' values (1,1,1 ... 1)
isPrime[0] = isPrime[1] = 0 // 0 and 1 are not prime numbers
primes.push(2); //first prime number. 2 is a special prime number because is the only even prime number.
for (i = 2; i * 2 <= 100000; i++) isPrime[i * 2] = 0 // remove all multiples of 2
for (i = 3; i <= 100000; i += 2) // check all odd numbers from 2 to 100000
if (isPrime[i]) {
primes.push(i); // add the new prime number to the solution
for (j = 2; i * j <= 100000; j++) isPrime[i * j] = 0; // remove all i's multiples
}
return primes
我希望你理解我的意见
答案 2 :(得分:0)
我理解一个素数是一个只能被自身整除的数字和数字1(没有余数)。见Wikipedia Article
话虽这么说,我在第二条评论中并没有很好地理解算法,但对你的算法的一个小改进是将你的for循环更改为:
for (int i = 5; i < 100000; i = i + 2) {
if (checkMod(i)) {
primes.add(i);
}
}
这是基于这样的假设,即1,2和3都是素数,此后所有偶数都不是素数。这至少可以将你的算法减少一半。
答案 3 :(得分:0)
我想对本杰明·阿曼(Benjamin Oman)上面提到的0ne做一个稍微改进的版本, 这只是一个修改,以避免检查以数字'5'结尾的所有数字的素数,因为这些数字肯定不是素数,因为它们可以被5整除。
for (int i = 7;(i < 100000) && (!i%5==0); i = i + 2) {
if (checkMod(i)) {
primes.add(i);
}
}
这是基于2,3,5是素数的假设。上述微小变化将减少5的所有因素并改善。
答案 4 :(得分:0)
@Daniel Fischer很好地解释了。
从他的解释中用C ++实现:
#include<iostream>
using namespace std;
long* getListOfPrimeNumbers (long total)
{
long * primes;
primes = new long[total];
int count = 1;
primes[0] = 2;
primes[1] = 3;
while (count < total)
{
long composite_number = primes[count] + 2;
bool is_prime = false;
while (is_prime == false)
{
is_prime = true;
for (int i = 0; i <= count; i++)
{
long prime = primes[i];
if (prime * prime > composite_number)
{
break;
}
if (composite_number % prime == 0)
{
is_prime = false;
break;
}
}
if (is_prime == true)
{
count++;
primes[count] = composite_number;
}
else
{
composite_number += 2;
}
}
}
return primes;
}
int main()
{
long * primes;
int total = 10;
primes = getListOfPrimeNumbers(total);
for (int i = 0; i < total; i++){
cout << primes[i] << "\n";
}
return 0;
}
答案 5 :(得分:0)
import array , math
print("enter a range to find prime numbers")
a= 0
b= 5000
c=0
x=0
k=1
g=[2]
l=0
for I in range( a , b):
for k in g:
x=x+1
if k>2:
if k > math . sqrt( I ):
break
if( I % k==0):
c=c+1
break
if c==0:
if I!=1:
g . append( I )
c=0
print g
#this algorithm will take only 19600 iteration for a range from 1-5000,which is one of fastest algorithm according to me
答案 6 :(得分:0)
我发现数学家说“ 3之后的素数始终是6的倍数的一侧”。 它的5,7质数接近6。 11,13也更接近6 2。 17,19也是6 3。 21,23也是6 * 4。 我既写正常代码,又写了多达一百万条代码,我发现该算法也是正确且更快的。?
num=1000000
prime=[2,3]
def test(i):
for j in prime:
if(i%j==0):
break
if(j*j>i):
prime.append(i)
break
return 0
for i in range (6,num,6):
i=i-1
test(i)
i=i+2
test(i)
i=i-1
print(prime)