当前位置: 首页 > 知识库问答 >
问题:

优化素数筛 (Java) 的速度

尉迟景福
2023-03-14

我正在Java中研究一种创建布尔数组isPrime的方法:

boolean[] isPrime;

其中质数用“真”标记,其余的用“假”标记。< br >同时,我还想数一数找到的素数:

int numPrimesFound;

基本思想是使用埃拉托斯特尼筛。到目前为止,我的方法看起来像这样:

public Sieve(final int limit) {

    long startTime = System.currentTimeMillis();

    boolean[] isPrime = new boolean[limit];
    this.isPrime = isPrime;

    for (int i=3; i<=limit ;i+=2) {
        isPrime[i] = true;                        //sets all even numbers to true
    }

    isPrime[2] = true;
    numPrimesFound = 1;                           //special case of '2'

    for (int i = 3; i * i <= limit; i += 2) {
        if (isPrime[i] == true) {
            for (int j = i; i * j <= limit; j += 2) {

                isPrime[i * j] = false;           //has a multiple ==> not a prime

                numPrimesFound++;                 //doesn't work yet
            }
        }
    }

    long stopTime = System.currentTimeMillis();   //measuring execution time
    System.out.println("Sieve: " + (stopTime - startTime) + " milliseconds.")

}

所以我的问题是

numPrimesFound++:

因为筛子多次将一些非质数的值设置为“false”(例如45 bcs 3*15=45和9*5=45),所以不起作用
那么,有人知道我如何重写这个程序,以便只将所有非质数设置为“false”一次吗?

或者一般来说,任何人都可以建议使方法更快吗?

共有3个答案

薛霄
2023-03-14

您感到困惑:

找到numPrimes;可以,但它必须在(int j=i;i*j)的循环之外

你的主循环必须走得更远(否则你忘记了大于sqrt(极限)的素数)

 for (int i = 3; i < limit; i += 2) 

在埃拉托斯特尼筛中,标记几次“非素数”是正常的。

和i*j

结果是可以的,但只能用

final int limit=40000; // 50 000 is too big !

用它代替你的内循环,你至少可以达到1000000。

 for (int z = i*2; z<limit; z+=i)
    isPrime[z] = false;           //has a multiple ==> not a prime

你可以用比特集

漆雕唯
2023-03-14

下面是我的版本(它只计算包含输入数的可能质因数的集合):

import java.util.BitSet;
import java.util.Scanner;

public class Main {

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println("Enter the interval limit: ");
    int limit = sc.nextInt();
    int max = (int) Math.sqrt(limit);
    long start = System.currentTimeMillis();
    BitSet intArray = new BitSet(max);

    // 1 is not prime
    intArray.set(0);

    // 2 is the first prime number, so the first step is to filter out all even numbers
    for (int i = 2; i < limit; i+=2) {
        intArray.set(i);
    }

    //all remaining number will be odd
    int currentNumber = 3;
    // i is the multiplicator and will be adjusted with the current number , in order to avoid repetition
    int i = 3;
    int temp;

    while (currentNumber <= max) {
        // flag multiple of the current prime number
        while (true) {
            temp = (currentNumber * i);
            if (temp > max) break;
            intArray.set(temp - 1);
            i += 2;
        }
        //all non-prime numbers until now are already flagged, therefore we can find the next prime number by checking the set-status.
        while (true) {
            currentNumber += 2;
            if (currentNumber > max) break;
            if (!intArray.get(currentNumber - 1)) {
                i = currentNumber;
                break;
            }
        }
    }

    int b = 0;
    for (int n = max -1 ; n > 0; n--){
        if (!intArray.get(n)){
            b = n + 1;
            break;
        }
    }
    System.out.println("There are " + (max - intArray.cardinality()) + " PRIMES and the biggest is: " + b);
    System.out.println("Time in total: " + ((System.currentTimeMillis() - start) / 1000.0) + "s");
}
}

要检查1亿个数字,我的i7 3770k台式电脑需要大约0,7秒。

商琛
2023-03-14

如果您使用 BitSet,则可以要求它的基数

public BitSet primes(final int limit) {

    long startTime = System.currentTimeMillis();
    BitSet isPrime = new BitSet(limit);
    // A bitSet starts all zeros but with a sieve - evrything must start prime.
    isPrime.flip(0, limit);

    // 0 and 1 are not prime
    isPrime.clear(0);
    isPrime.clear(1);

    for (int i = 2; i * i <= limit; i += 2) {
        if (isPrime.get(i)) {
            // Remove all multiples of i.
            for (int j = 2; i * j <= limit; j += 1) {
                isPrime.clear(i * j);
            }
        }
    }

    long stopTime = System.currentTimeMillis();   //measuring execution time
    System.out.println("Sieve: " + (stopTime - startTime) + " milliseconds.");
    return isPrime;
}

public void test() {
    BitSet primes = primes(50);
    System.out.println("Primes: " + primes);
    System.out.println("Count: " + primes.cardinality());
}

我还修复了你逻辑中的几个错误。E、 g.你的内循环是按2步进j,而你的外循环不是删除所有偶数(从 >开始)。

你当然可以改进这一点——谷歌是你的朋友。:)

 类似资料:
  • 热点数据怎么筛选? 如题,存在这样一个场景,上游系统和我们系统之间存在通知+定时轮询的机制去同步某个账户的流水。其中定时轮询的批量高频率执行,因为里面大部分账户做同步的时候都是没有任何数据的,上游系统就骂人了,由此打算从中抽取一些热点数据做同步。 现在的想法是在得到通知的时候维持一个redis缓存,定时轮询时看缓存中是否存在数据,存在才同步否则不同步,然后再做一个慢一点的全量同步定时。具体实现是在

  • HiI在网上看到了一个计算一个数的不同素因子的答案,它看起来不是最优的。所以我试图改进它,但在一个简单的基准测试中,我的变体比原始版本慢得多。 该算法计算一个数的不同质因数。最初使用一个HashSet来收集因子,然后使用size来获得它们的数目。我的“改进”版本使用了一个int计数器,并将while循环分解为if/while以避免不必要的调用。 更新:tl/dr(有关详细信息,请参阅接受的答案)

  • 我正在尝试欧拉项目的问题3,我的算法太慢了。有人知道如何优化它吗?我试图计算的数字是600851475143L。计算这个需要很长时间,所以我需要一种方法来加快计算速度。 逻辑: > 把从3到1的所有数字通读一遍 对于这些数字中的每一个,通过将它们除以中间的所有数字来检查它们是否为素数,如果它们不除以任何一个,则它们为素数 如果为素数,则将其添加到数组中。 **********更新*********

  • 问题内容: 我纯粹是出于问题的速度方面而问这个问题。 在对象是私有或公共(Java)时从对象获取值之间在速度上有什么区别? 我知道我可以测试它,但是如果任何人都知道,它就不会受伤:)预先感谢! 问题答案: 公共和私有访问无非就是在编译时确定您是否有权访问变量。在运行时,它们完全相同。这意味着,如果您可以诱使JVM认为您具有访问权限(通过反射,不安全或修改字节码),则可以。公共和私人只是编译时间信息

  • 在完成一个模块后,应该从那几个方面对代码进行优化,有哪些方法可以进行优化

  • 问题内容: 我想知道两者之间是否有任何性能差异 字符串s = someObject.toString(); System.out.println(s); 和 System.out.println(someObject.toString()); 查看生成的字节码,似乎有所不同。JVM是否能够在运行时优化此字节码,以使两个解决方案提供相同的性能? 在这种简单情况下,当然解决方案2似乎更合适,但有时出于