找出200万以下所有素数的总和。我的程序不适用于非常大的数字

时间:2015-04-23 06:40:28

标签: java algorithm primes

这是我找到素数总和的代码。它适用于一些较低的数字,但如果它2000000(200万)它永远不会结束。任何人都可以帮助我吗?

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); 
    }
}

6 个答案:

答案 0 :(得分:9)

你的答案是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),这会大大改善你的代码运行时间:)

答案 1 :(得分:3)

@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;
}

答案 2 :(得分:2)

你可以使用Sieve of Eratosthenes算法,它比你的效率更高。

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值的和索引

答案 3 :(得分:2)

一个有效的解决方案可能是使用Sieve of Eratosthenes来找出低于2,000,000(或任何其他数字)的数字,而不是后处理并将它们全部加起来:

    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)额外空间。

答案 4 :(得分:0)

我开发了自己的解决方案,它能在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;
}

答案 5 :(得分:-1)

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