我有一个问题要打印一百万个素数。我已经为此编写了一个java程序。它目前需要1.5分钟来计算它。我认为我的解决方案效率不高。我使用了以下算法:
我也读过其他几个解决方案,但我没有找到一个好的答案。请在理想情况下建议计算此值的最短时间应该是什么,以及需要进行哪些更改才能使算法更有效。
答案 0 :(得分:12)
如果您在列表中添加了1,那么您的答案已经错误了:)
无论如何,Sieve of Erathosthenes是您应该开始的地方,它非常简单且非常有效。
一旦你熟悉了筛子的概念及其工作方式,你就可以继续Sieve of Atkin,这有点复杂,但显然效率更高。
答案 1 :(得分:4)
关键词:
答案 2 :(得分:3)
您可能希望实施Sieve of Eratosthenes算法以查找从1到n
的素数,并在需要时迭代地增加范围。 (即没有找到1,000,000个素数)
答案 3 :(得分:2)
一个简单的Eratosthenes筛子就像拍板一样。这会在不到一秒的时间内计算出第1,000,000个素数:
class PrimeSieve
{
public List<int> Primes;
private BitArray Sieve;
public PrimeSieve(int max)
{
Primes = new List<int> { 2, 3 }; // Must include at least 2, 3.
Sieve = new BitArray(max + 1);
foreach (var p in Primes)
for (var i = p * p; i < Sieve.Length; i += p) Sieve[i] = true;
}
public int Extend()
{
var p = Primes.Last() + 2; // Skip the even numbers.
while (Sieve[p]) p += 2;
for (var i = p * p; i < Sieve.Length; i += p) Sieve[i] = true;
Primes.Add(p);
return p;
}
}
编辑:最佳筛选从p ^ 2开始,而不是2p,正如Will Ness正确指出的那样(低于p ^ 2的所有化合物编号都会在早期迭代中标记出来。)
答案 4 :(得分:2)
首先,1不是素数。
其次,第一百万个素数是15,485,863,所以你需要为一些大数据处理做好准备。
第三,你可能想要使用Eratosthenes的Sieve;这是一个简单的版本:
function sieve(n)
bits := makeArray(0..n, True)
for p from 2 to n step 1
if bits[p]
output p
for i from p*p to n step p
bits[i] := False
这可能不适用于计算第一百万个素数所需的数组大小。在这种情况下,您需要实现Eratosthenes的分段筛。
我在我的博客上与prime numbers做了很多工作,其中包括一个essay,它提供了一个优化的Eratosthenes Sieve,并使用五种编程语言实现。
无论你做什么,使用任何编程语言,你都应该能够在不超过几秒的时间内计算出第一百万个素数。
答案 5 :(得分:1)
这是一个实现Trial division sieve的Ocaml程序(正如Will正确指出的那样,是Eratosthenes的反转):
(* Creates a function for streaming integers from x onward *)
let stream x =
let counter = ref (x) in
fun () ->
let _ = counter := !counter + 1 in
!counter;;
(* Filter the given stream of any multiples of x *)
let filter s x = fun () ->
let rec filter' () = match s () with
n when n mod x = 0 ->
filter' ()|
n ->
n in
filter' ();;
(* Get next prime, apply a new filter by that prime to the remainder of the stream *)
let primes count =
let rec primes' count' s = match count' with
0 ->
[]|
_ ->
let n = s () in
n :: primes' (count' - 1) (filter s n) in
primes' count (stream 1);;
它适用于整数流。每次发现新的素数时,都会向流中添加一个过滤器,以便对该流的其余部分过滤掉该素数的任何倍数。可以更改此程序以生成素数按需。
在Java中采用相同的方法应该相当容易。
希望这有帮助!
答案 6 :(得分:1)
实际上,只需 2 个就足够了。硬编码 3 最多可以节省一毫秒。没有必要在 1 上竖琴。我确信包含它是一个诚实的错误。您已经知道了,参与该计划将有助于证实这一点。
<块引用>最后一个数字?在什么基地?基数 10?我想这可能是你的问题。
<块引用>我认为这就是问题所在。您的程序应该简单地跳过偶数,因为除了 -2 和 2,它们都是合数。另一方面,这不会使运行时间减半,因为像 91 和 2209 这样的奇数可能需要更多的努力才能排除不是质数。
<块引用>“2 直到数字的平方根”是否包括像 4、6 和 9 这样的数字?唯一需要检查的潜在因素是已经被证明为素数的数字。如果 n 不能被 7 整除,它也不能被 49 整除。如果你正在建立一个列表,你不妨用它来检查潜在的素数。
对 Java 进行基准测试有点困难,因为您受运行时系统的支配。尽管如此,一分半钟,虽然被梅森认为是奇迹,但今天太慢了。五、十秒,我认为可以接受。
也许这是您应该避免使用对象以支持原始数组的情况之一。我的初稿比你的还要长。最后我想出了这个:
static int[] fillWithPrimes(int quantity) {
int[] primes = new int[quantity];
primes[0] = 2;
int currPi = 1;
int currIndex = 0;
int currNum = 3;
int currPrime;
boolean coPrimeFlag;
double squareRoot;
while (currPi < quantity) {
squareRoot = Math.sqrt(currNum);
do {
currPrime = primes[currIndex];
coPrimeFlag = (currNum % currPrime != 0);
currIndex++;
} while (coPrimeFlag && currPrime <= squareRoot);
if (coPrimeFlag) {
primes[currPi] = currNum;
currPi++;
}
currNum += 2;
currIndex = 0;
}
return primes;
}
然后我写了一个 main()
记录调用 fillWithPrimes()
之前的时间,参数为 1,000,000,并报告结果:
运行:
操作耗时 2378 毫秒
第 10 个质数是 29
第 100 个质数是 541
第 1000 个质数是 7919
第 10000 个质数是 104729
第 100000 个质数是 1299709
第 1000000 个质数是 15485863
构建成功(总时间:2 秒)
我相信它可以进一步优化。就我个人而言,我对两秒半感到满意。
答案 7 :(得分:0)
这是一个使用递归和迭代达到百万分之一素数的javascript解决方案。它不像Erathosthenes的筛子那么快,但不需要提前知道百万个素数的值(即所需筛子的大小):
function findPrimes(n, current, primes) {
if (!n || current < 2) return []
var isPrime = true
for (var i = 0; i < primes.length; i++) {
if (current % primes[i] == 0) {
isPrime = false
break
}
}
if (isPrime) primes.push(current)
if (primes.length < n) return findPrimes(n, current + 1, primes)
else return primes
}
var primes = [2,3]
for (var i = 1; i <= 1000; i++) {
primes = findPrimes(i*1000, primes[primes.length - 1]+1, primes)
console.log(i*1000 + 'th prime: ' + primes[primes.length-1])
}
process.exit()
输出:
...
996000th prime: 15419293
997000th prime: 15435941
998000th prime: 15452873
999000th prime: 15469313
1000000th prime: 15485863
Process finished with exit code 0
答案 8 :(得分:0)
作为一个较新的水平,我将尝试该水平,因此,对其进行更有效,更快速的改进表示赞赏。
public static void main(String ar[]) {
ArrayList primeNumbers = new ArrayList();
for(int i = 2; primeNumbers.size() < 1000000; i++) {//first 1 million prime number
// for(int i = 2; i < 1000000; i++) {//prime numbers from 1 to 1 million
boolean divisible = false;
for(int j=2;j<i/2;j++){
if((i % j) == 0) {
divisible = true;
break;
}
}
if(divisible == false) {
primeNumbers.add(i);
// System.out.println(i + " ");
}
}
System.out.println(primeNumbers);
}
答案 9 :(得分:-1)
5之后的所有内容都不会被5整除,所以你可以跳过正确的事情(1,麻木)&lt;&gt;&#34; 5&#34;例如987,985。我在Excel中制作了一个将测试一百万个素数的素数并在大约15秒钟内将它们吐在一个列中但它在1500万左右疯狂