找到给定范围内的所有素数

时间:2012-02-24 22:10:01

标签: java primes sieve-of-eratosthenes

我正在编写这个Java程序,它找到给定范围之间的所有素数。因为我正在处理非常大的数字,我的代码似乎不够快,并给我一个时间错误。这是我的代码,有谁知道让它更快?感谢。

import java.util.*;
public class primes2 
{   
    private static Scanner streamReader = new Scanner(System.in);
    public static void main(String[] args)
    {
        int xrange = streamReader.nextInt(); 
        int zrange = streamReader.nextInt();
        for (int checks = xrange; checks <= zrange; checks++)
        {
            boolean[] checkForPrime = Primes(1000000);
            if (checkForPrime[checks])
            {
                System.out.println(checks);
            }
        }
    }
    public static boolean[] Primes(int n)
    {
        boolean[] isPrime = new boolean[n + 1];
        if (n >= 2)
            isPrime[2] = true;
        for (int i = 3; i <= n; i += 2)
            isPrime[i] = true;
        for (int i = 3, end = sqrt(n); i <= end; i += 2)
        {
            if (isPrime[i]) 
            {
                for (int j = i * 3; j <= n; j += i << 1)
                    isPrime[j] = false;
            }
        }
        return isPrime;
    }
    public static int sqrt(int x)
    {
        int y = 0;
        for (int i = 15; i >= 0; i--) 
        {
            y |= 1 << i;
            if (y > 46340 || y * y > x)
                y ^= 1 << i;
        }
        return y;
        }
}

3 个答案:

答案 0 :(得分:7)

只需更改此内容即可获得巨大的改进:

    for (int checks = xrange; checks <= zrange; checks++)
    {
        boolean[] checkForPrime = Primes(1000000);

到此:

    boolean[] checkForPrime = Primes(1000000);
    for (int checks = xrange; checks <= zrange; checks++)
    {

您当前的代码会重新生成筛子zrange - xrange + 1次,但实际上您只需要生成一次。

答案 1 :(得分:0)

显而易见的问题是你多次计算质量达到1000000(zrange - xrange次)。另一个是你不需要计算高达1000000的素数,你只需要检查素数到zrange,所以你在zrange&lt; 1000000,并在zrange&gt;时获得缓冲区溢出百万。

答案 2 :(得分:0)

您可以从i*i开始内循环,即代替for (int j = i * 3; j <= n; j += i << 1),您可以编写for (int j = i * i; j <= n; j += i << 1)以获得较小的加速。

此外,您必须确保zrange不大于1000000

如果xrange远大于sqrt(zrange),您还可以将筛阵列拆分为两个,用于偏移筛方案。较低的数组将从2到sqrt(zrange)。较高的一个将从xrange延伸到zrange。当您筛选出较低的数组时,每个新的素数都会被它识别出来,在您的内部循环中,除了将较低的数组标记到其末端之外,还要筛选上部数组。您将必须计算每个素数i的起始偏移量,并使用与2*i相同的步骤,就像对下半部分一样。如果你的范围比几个素数更宽,你将获得速度优势(否则只需按赔率划分试验即可)。

另一件事是,如果evens > 2不是素数,为什么要在阵列中代表它们并浪费一半的空间?您可以将每个i视为代表奇数2*i+1,从而压缩您的数组。

最后一个简单的技巧是通过标记ON而不仅仅是odds(即2的复制品)来预先消除3 的倍数{ ... i+=2; ...}2,而3只有{ ... i+=2; ... i+=4; ... } OFF的副本。此外,在标记> 3倍数的{ ... j+=2*i; ... j+=4i; ...}时,也请使用5*5, 5*7, 5*9, 5*11, ...。例如,在OFF中,如果5*9的多个3未标记为ON,则无需标记{{1}} {{1}}。