如何找到2000000以下的Primes总和?

时间:2016-04-01 04:39:29

标签: java integer-overflow

public static void main(String[] args) {
    int sum = 2;
    int isPrime;
    for(int x = 3; x < 2000000; x+=2){//x is the number we check for if it is a prime
        isPrime = 0;
        int y = 3;
        while(isPrime == 0) {
            if(x%y==0){
                isPrime = 1;
            }
            if(y > Math.ceil(x/2)) {
                isPrime = 1;
                sum+=x;
            }
            y += 2;
        }
    }
    System.out.println(sum);
}

所以我试图找到低于2 000 000的素数之和,我已经检查过,这个代码适用于x&lt;我无法弄清楚当接近2 000 000时会发生什么情况,但有些事情确实存在。如果你能找到原因,我将不胜感激。

5 个答案:

答案 0 :(得分:3)

这是因为名为integer overflow的东西。简而言之,它指的是计算机中的整数具有最大位数(即二进制数字)的概念。 int最多包含32位,这意味着无符号系统中可能的最大数量为2^32-1。如果你在这个数字上加1,你得到0,因为没有更多数字可以携带1!

因此,对于您的代码,使用long(具有64位限制):

long sum = 2;
for(int i = 3 ; i < 2000000 ; i+=2) if(/*i is Prime*/) sum += i;
System.out.println(sum);

这是一个解释它是什么的YouTube video

答案 1 :(得分:2)

Java中的

int签名号码,其中最大可能值为2 31 - 1.由于您的最大值约为200万,您只能需要超过1000个这个大小的值才能超过约20亿的限制。超过此限制时,int类型保留最低32位,而不是抛出错误,这看起来像一个理智的结果,但实际上是错误的。

BTW您可以通过替换

来查看何时发生这种情况
sum+=x;

sum = Math.addExact(sum, x);

检查溢出。

public static int addExact(int x, int y) {
    int r = x + y;
    // HD 2-12 Overflow iff both arguments have the opposite sign of the result
    if (((x ^ r) & (y ^ r)) < 0) {
        throw new ArithmeticException("integer overflow");
    }
    return r;
}

我建议使用long,其限额约为9亿亿美元。

BTW如果您需要所有素数达到已知限制,使用Sieve of Eratosthenes可能是一种更有效的解决方案。如果要随机检查数字,搜索数字的所有可能因素往往会更有效。

以下是我将如何编写使用long并简化代码的方法。

public static void main(String... args) {
    long sum = 2;
    for(int x = 3; x < 2000000; x += 2) 
        if (isPrime(x)) 
           sum += x;

    System.out.println(sum);
}

/**
 * @param x is the number we check for if it is a prime
 */
static boolean isPrime(long x) {
    if (x % 2 == 0) 
        return false;
    for (int y = 3; y * y <= x; y += 2) 
        if (x % y == 0) 
            return false;
    return true;
}

答案 2 :(得分:1)

你的程序有2个问题,第一个由@Malijam指定,答案会溢出。

第二个是关于复杂性O(n^2)最坏的情况。这太多了。

您可以通过检查小于候选数字平方根的因子来稍微修改您的代码O(n * sqrt(n))

修改后的代码:

public static void main(String[] args) {
    long sum = 2;
    long isPrime;
    for(int x = 3; x < 2000000; x+=2){//x is the number we check for if it is a prime
        isPrime = 0;
        long y = 3;
        while(isPrime == 0) {
            if(x%y==0){
                isPrime = 1;
            }
            if(y*y > x) {
                isPrime = 1;
                sum+=x;
            }
            y += 2;
        }
    }
    System.out.println(sum);
}

Ideone上的演示:http://ideone.com/k1XAuA

答案 3 :(得分:0)

您的代码似乎可以在我的计算机上运行。代码打印1179908154,与uSeemSurprised的答案中显示的不同,但它应该让你输出。算术程序花了很长时间(大约2分钟),但它工作正常。根据计算机的功率,可能需要很长时间。

PS:我做了一些修改,使程序没有花费那么长时间。我转身

if(y> Math.ceil(x / 2))

如果(Y * 3 X的催化剂)

当您运行数百万次代码时,调用Math.ceil非常低效。我认为乘法也比分裂快。我还在for循环之外移动了int的声明。结果代码的速度是原来的三倍。

答案 4 :(得分:0)

一般答案: 您可以在下面的代码中找到所有素数中的一些:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
   long long int tc,N;
    unsigned long long int sum=0;
   vector <long long int>v;
    long long int arr[1000000] = {0},i,j;
    for (i = 2; i < 1000000; i++)
    {
        for ( j = i * i; j < 1000000; j+=i)
        {
            arr[j - 1] = 1;
        }
    }
    for (int i = 1; i < 1000000; i++)
    {
        if (arr[i - 1] == 0)
            v.push_back(i);
    }
       cout<<"\nEnter the number:";
       cin>>N;
       i=1;
       while(v.at(i)<=N)
       {
           sum+=v.at(i);
           i++;
       }
       cout<<sum<<"\n";
       sum=0;

   return 0;
}