简体   繁体   English

高效素数计算程序Java

[英]Efficient Prime Number Computing Program Java

So I was trying to make a prime number calculator in java that goes from 1 up to the upper limit of the range given by the user and prints out all of the primes. 所以我试图在Java中制作一个质数计算器,该质数从1到用户给定范围的上限,并打印出所有质数。

One way of approaching this was by simply using a nested for loop and testing divisibility for every number in the range by all of the numbers less than it. 解决此问题的一种方法是,仅使用嵌套的for循环,并通过小于该范围的所有数字来测试范围内每个数字的可除性。

However, I figured it would be more efficient to only test prime numbers to avoid repeated factors and speed up the program. 但是,我认为只测试质数以避免重复的因素并加快程序的效率会更高。

For example, if the number we were on was 16, rather than testing if it's divisible by 2,3,4,5,...14,15,16, I could only test out 2,3,5,7,11,13 and stop once a factor is found. 例如,如果我们使用的数字是16,而不是测试是否可以被2,3,4,5,... 14,15,16整除,那么我只能测试2,3,5,7,11 ,13,一旦发现一个因素就停止。

So I tried to make an array to store all of the primes found so far and only use those values to test for the next number. 因此,我尝试创建一个数组来存储到目前为止找到的所有素数,并且仅使用这些值来测试下一个数字。

Here's my code, I can't figure out why it's not working 这是我的代码,我不知道为什么它不起作用

    Scanner sc = new Scanner (System.in);
    System.out.print ("Enter the upper limit: ");
    int high = sc.nextInt();

    boolean isPrime = true;
    int[] primearray = new int[0];

    for (int num = 1; num <= high; num++)
    {
        for (int x: primearray)
        {
            if (num%x==0)
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime == true) {
            int size = primearray.length;
            primearray = new int[size+1];
            primearray [size] = num;

            System.out.println (num);
        }
    }

First of all, 1 isn't prime. 首先,1不是质数。 By starting your outer loop at 1, your prime array ends up with 1 in it and everything else will then test as not prime. 通过在1处开始外循环,您的质数数组最终以1结束,然后其他所有条件将测试为非质数。 Start your outer loop at int num = 2 . int num = 2开始您的外部循环。

Second, you aren't copying over the existing known primes when you expand primearray . 其次,展开primearray时,不会复制现有的已知素数。 You can use 您可以使用

primearray = Arrays.copyOf(primearray, size+1);

which will make a new array with all the old contents copied and space for one more value. 这将创建一个新的数组,其中复制了所有旧内容,并保留了一个更大的值。

Finally, you might want to check out the Sieve of Eratosthenes . 最后,您可能需要查看Eratosthenes筛网 A careful implementation of that algorithm will be more efficient than your current algorithm, which requires an expensive array reallocation every time you find a prime. 谨慎地实现该算法将比当前算法更有效,因为当前算法每次找到素数都需要进行昂贵的数组重新分配。 You can use a BitSet to keep track of the flags that the sieve needs. 您可以使用BitSet来跟踪筛子需要的标志。

You have wrong in logic 你逻辑错了

boolean isPrime = true;

this variable should be declared in for loop, let 's imagine, if you find out 4 is not prime then isPrime = false , then you check 5 but there is not any code block that set isPrime = true . 假设应该在for循环中声明此变量,让我们想象一下,如果发现4不是素数,则isPrime = false ,然后检查5但是没有任何代码块设置isPrime = true

And this block: 和这个块:

if (isPrime == true) {
    int size = primearray.length;
    primearray = new int[size+1];
    primearray [size] = num;

    System.out.println (num);
}

You created new array of prime number, primearray with size increased by 1, so primearray does not contain any old prime number, that will make wrong while checking prime. 你创造了素数的新阵列, primearray与大小增加1,那么primearray不包含任何旧的素数,同时检查主要是将做出错误的。 So you need to copy old prime numbers to new array. 因此,您需要将旧质数复制到新数组。

And because the prime numbers start by 2, so your code should be: 并且由于质数以2开头,因此您的代码应为:

Scanner sc = new Scanner(System.in);
System.out.print("Enter the upper limit: ");
int high = sc.nextInt();

int[] primeArray = new int[0];
for (int num = 2; num <= high; num++)
{
    boolean isPrime = true;
    for (int x : primeArray)
    {
        if (num % x == 0)
        {
            isPrime = false;
            break;
        }
    }

    if (isPrime == true)
    {
        primeArray = Arrays.copyOf(primeArray, primeArray.length + 1);
        primeArray[primeArray.length - 1] = num;
        System.out.println(num);
    }
}

You should use a Sieve of Eratosthenes to find primes, rather than testing each number for divisibility; 您应该使用Eratosthenes筛子来查找素数,而不是测试每个数的可除性; that method is far slower than sieving. 该方法比筛分要慢得多。 Here is an implementation of sieving from my blog : 这是从我的博客中筛选的一种实现:

public static LinkedList sieve(int n)
{
    BitSet b = new BitSet(n);
    LinkedList ps = new LinkedList();

    b.set(0,n);

    for (int p=2; p<n; p++)
    {
        if (b.get(p))
        {
            ps.add(p);
            for (int i=p+p; i<n; i+=p)
            {
                b.clear(i);
            }
        }
    }

    return ps;
}

As you say the key simplification is to only test primes when you find the next prime. 正如您所说,简化的关键是仅在找到下一个素数时才测试素数。 For example: 例如:

public class PrimeGenerator {
    private long current = 1;
    private final List<Long> primes = new ArrayList<>();

    public long next() {
        do {
            current++;
        } while (primes.stream().anyMatch(n -> current % n == 0));
        primes.add(current);
        return current;
    }

    public LongStream stream() {
        return LongStream.generate(this::next);
    }
}

This records each prime as it is generated. 这记录了每个素数的生成。

You can generate get all primes to a certain value with 您可以使用生成所有素数到一定值

generator.stream().takeWhile(p -> p < value)...

Previous answers already explains what is wrong with your code. 先前的答案已经解释了您的代码有什么问题。

I just want to share another approach which is more efficient. 我只想分享另一种更有效的方法。 The sample implementation is as per below. 示例实现如下。 Basically, once we know x is prime number, we also know i*x is NOT a prime number. 基本上,一旦我们知道x是质数,我们也知道i * x不是质数。 Further reading and visualization is available here 在此处进一步阅读和可视化

public int countPrimes(int n) {
            if (n == 0 || n == 1) return 0;

    int count = 0;
    boolean[] check = new boolean[n+1];

    for (int i = 2; i < n; i++) {
        if (check[i]) continue;

        for (int j = 1; j <= n / i; j++) {
            check[j * i] = true;
        }

        count++;
    }

    return count;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM