求小于 2000000 的素数之和
Finding sum of primes below 2000000
public static void main(String[] args) {
int sum = 2;
int isPrime;
for(int x = 3; x < 2000000; x+=2){
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);
}
上面的代码适用于 x < 1000,但我得到 x = 2000000 的错误答案,我无法理解原因。
是因为一个叫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 解释它是什么。
您的程序有 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
int
in Java 是一个 signed 数,其中最大可能值为 231 - 1 . 由于您的最大值约为 200 万,因此您只需要 1000 多个这种大小的值,总和就会超过约 20 亿的限制。当超过这个限制时,int
类型保留最低的 32 位,而不是抛出错误,这看起来是一个正常的结果,但实际上是不正确的。
顺便说一句,您可以通过替换
来查看何时发生这种情况
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
~ 90 亿。
顺便说一句,如果您需要所有素数达到已知限制,使用 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;
}
你的代码似乎可以在我的电脑上运行。代码打印出 1179908154,这与 uSeemSurprised 的答案中显示的不同,但它应该给了你一个输出。算术程序花了很长时间(大约 2 分钟),但运行良好。根据您计算机的性能,这可能需要很长时间。
PS:我做了一些改动,使程序的运行时间不那么长。我转了
if(y > Math.ceil(x/2))
至
如果(y*3>x)
当您 运行 代码数百万次时,调用 Math.ceil 确实效率低下。我认为乘法也比除法快。我还将 int y 的声明移到了 for 循环之外。结果代码的速度是原来的三倍。
笼统的回答:
你和通过下面的代码找到一些直到n的所有质数:
#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;
}
public static void main(String[] args) {
int sum = 2;
int isPrime;
for(int x = 3; x < 2000000; x+=2){
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);
}
上面的代码适用于 x < 1000,但我得到 x = 2000000 的错误答案,我无法理解原因。
是因为一个叫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 解释它是什么。
您的程序有 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
int
in Java 是一个 signed 数,其中最大可能值为 231 - 1 . 由于您的最大值约为 200 万,因此您只需要 1000 多个这种大小的值,总和就会超过约 20 亿的限制。当超过这个限制时,int
类型保留最低的 32 位,而不是抛出错误,这看起来是一个正常的结果,但实际上是不正确的。
顺便说一句,您可以通过替换
来查看何时发生这种情况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
~ 90 亿。
顺便说一句,如果您需要所有素数达到已知限制,使用 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;
}
你的代码似乎可以在我的电脑上运行。代码打印出 1179908154,这与 uSeemSurprised 的答案中显示的不同,但它应该给了你一个输出。算术程序花了很长时间(大约 2 分钟),但运行良好。根据您计算机的性能,这可能需要很长时间。
PS:我做了一些改动,使程序的运行时间不那么长。我转了
if(y > Math.ceil(x/2))
至
如果(y*3>x)
当您 运行 代码数百万次时,调用 Math.ceil 确实效率低下。我认为乘法也比除法快。我还将 int y 的声明移到了 for 循环之外。结果代码的速度是原来的三倍。
笼统的回答: 你和通过下面的代码找到一些直到n的所有质数:
#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;
}