求两个以下所有质数的总和 million.My 程序不适用于非常大的数

Find the sum of all the primes below two million.My program doesn't work for very big numbers

这是我用于计算 primes.It 之和的代码,它适用于一些较小的数字,但如果它是 2000000(200 万),它永远不会 ends.Anybody 可以帮助我?

import java.math.BigInteger;
public class Problem010{
    public static void main(String[] args) {

        BigInteger sum = new BigInteger("2");

        //for (int i=3; i<2000000; i++) {
        for(int i=3; i<10; i++){
            for (int j=2; j<i; j++){
                if (i % j == 0) 
                    break;
                else if (i == j+1){
                    sum = sum.add(BigInteger.valueOf(i));
                }
            }
        }
        System.out.println("Sum  = "+sum); 
    }
}

你的答案是 142913828922,但如何回答?

我只是稍微改变了你的算法:

public static void main(String[] args) {

    BigInteger sum = new BigInteger("2");
    boolean isPrime = true;
    for (int i=3; i<2000000; i++) {
    double aa = Math.sqrt((double)i);
        for (int j=2; j<=aa; j++){
            if (i % j == 0){ 
                isPrime = false;
                break;
            }
        }
        if(isPrime){
            sum = sum.add(BigInteger.valueOf(i));
        }
        isPrime = true;
    }
    System.out.println("Sum  = "+sum); 
}

我没有遍历从 2 到 i 的所有数字,而是从 2 到 sqrt(i),这大大改善了您的代码 运行 时间 :)

@Lrrr,回答正确。但算法可以进一步优化。看看我的 isPrime 算法。对于 200 万,您不需要 BigInteger

    long sum = 2;// new BigInteger("2");
    for (int i=3; i<2000000; i++) {
        if(isPrime(i)) {
            sum = sum + i;//.add(BigInteger.valueOf(i));
        }    
    }
    System.out.println("Sum  = "+sum);

这是 isPrime 方法。

 static boolean isPrime(int n) {
    if (n < 2) {
        return false;
    }
    if (n == 2 || n == 3) {
        return true;
    }
    if ((n & 1) == 0 || n % 3 == 0) {
        return false;
    }
    int sqrtN = (int) Math.sqrt(n) + 1;
    for (int i = 6; i <= sqrtN; i += 6) {// loop 6 step
        if (n % (i - 1) == 0 || n % (i + 1) == 0) {
            return false;
        }
    }
    return true;
}

你可以用埃拉托色尼筛法,比你的效率高

1) 将2到N之间的所有数存入数组,并标记为素数

2) 从X = 2开始,将其所有的i*X(2X,3X..)标记为非素数,其中i为小于或等于N的自然数。不打X.

3) 找到下一个大于 X 的未标记的数字,然后重复该过程。如果没有这个数字,就停止。

4) 数组中剩余的数字是质数

像这样:

public static boolean[] findPrimes (int N) {

    boolean[] primes = new boolean[N + 1];

    // assume that all numbers are prime within given range
    for (int i = 2; i <= N; i++) {
        primes[i] = true;
    }

    // for all numbers in range, starting from 2
    for (int i = 2; i*i <= N; i++) {

        // mark natural multiples of i as nonprime
        if (primes[i]) {
            for (int j = i; i*j <= N; j++) {
                primes[i*j] = false;
            }
       }

 return primes;
}

5) 迭代返回的素数和 TRUE 值的求和索引

一个有效的解决方案可能是使用 Sieve of Eratosthenes 找出哪个数字是低于 2,000,000(或任何其他数字)的质数,然后 post- 处理并对它们求和:

    int n = 2000000;
    boolean[] isPrime = new boolean[n];
    //preprocess - set up the array
    for (int i = 2; i<n;i++) isPrime[i] = true;
    //run sieve:
    for (int i = 2; i < (int) Math.sqrt(n) + 1; i++) { 
        if (isPrime[i]) {
            for (int j = 2; j*i < n; j++) isPrime[i*j] = false;
        }
    }
    //sum primes:
    long sum = 0;
    for (int i = 2; i < n; i++) { 
        if (isPrime[i]) sum+=i;
    }
    System.out.println(sum);

与一次检查每个数字是否为素数相反(这需要 O(sqrt(n)) - 通过对所有数字执行此操作,您会得到 O(nsqrt(n)),在这里您可以汇总知识从以前的迭代中,有效地将复杂性降低到 O(nloglog(n)),对于足够大的 n 值,这明显更快。
这需要额外 O(n) 的成本 space。

到目前为止,还没有人真正正确地实施过 Sieve。仔细检查维基百科页面并注意你是如何循环数字的。如果不使用 int (或布尔值)数组进行任何优化,它应该只需要几秒钟 Java.

我开发了自己的解决方案,它在 700 毫秒内完成查找所有低于 200 万的内容。

我使用迭代方法,但我只是停止寻找大于 (n/i)+1 的数字,其中 n 是要检查的数是否为质数,i 是迭代循环中的数以查看它是否是除数。

public void run () {
    long sumOfPrimes = 2;
    int maxNumber = 2000000;
    int counter = 0;

    for (int i = 3; i <= maxNumber; i = i+2) {
        if(isPrimeOptimized(i)){
            sumOfPrimes = sumOfPrimes + i;
            counter ++;
        }
    }
    System.out.println("num of primes is " + counter);
    System.out.println("sum of primes is " + sumOfPrimes);
}

private boolean isPrimeOptimized(int n){
    int limitToDivide = n;
    for(int i=2;i<=limitToDivide && i<n;i++){
        if(n%i == 0)
            return false;
        else
            limitToDivide = (n/i) + 1;
    }
    return true;
}