为什么此代码未显示10 ^ 5左右的n的输出

时间:2019-04-20 19:17:23

标签: c++

我有以下代码用于计算形式不超过N的x ^ 2 + ny ^ 2质数。当N大约为80000时此代码运行良好,但是当N大约为10 ^ 5时该代码崩溃了。为什么会发生这种情况以及如何解决呢?

#include <iostream>
#include<iostream>
#include<vector>

const int N = 100000; //Change N in this line

using namespace std;
typedef long long int ll;
bool isprime[N] = {};
bool zprime[N] = {};
vector<int> primes;
vector<int> zprimes;
void calcprime(){
    for (int i = 2; i < N; i+=1){isprime[i] = true;}
    for (int i = 2; i < N; i+=1){
        if (isprime[i]){
            primes.push_back(i);
            for (int j = 2; i*j < N; j+=1){
                isprime[i*j] = false;
            }
        }
    }
}
void zcalc(){
    int sqrt = 0; for (int i = 0; i < N; i+=1){if(i*i >= N){break;} sqrt = i;}
    for (int i = 0; i <= sqrt; i +=1){
        for (int j = 0; j <= sqrt; j+=1){
            ll q = (i*i)+(j*j);
            if (isprime[q] && !zprime[q] && (q < N)){
                    zprimes.push_back(q);
                    zprime[q] = true;
            }
        }
    }
}
int main(){
   calcprime();
   zcalc();
   cout<<zprimes.size();
   return 0;
}

2 个答案:

答案 0 :(得分:4)

为什么代码会中断

超出范围的访问权限。该代码中断,因为您在此处对以下行进行了超出范围的内存访问:

    if (isprime[q] && !zprime[q] && (q < N)) {

如果q大于N,则说明您正在访问的内存在技术上不属于您。这会调用未定义的行为,如果N足够大,则会导致代码中断。

如果我们更改顺序以使其在进行其他检查之前先检查q < N,则不会出现此问题:

    // Does check first
    if((q < N) && isprime[q] && !zprime[q]) {

不建议将非常大的c数组用作全局变量。它可能会引起问题并增加可执行文件的大小。

(可能)非常大的全局数组。您将isprimezprime定义为c数组:

bool isprime[N] = {};
bool zprime[N] = {};

这可能会为N的很大的值带来问题,因为c-arrays是静态分配内存的。

如果将isprimezprime更改为向量,则即使N的值大于一千万,程序也会编译并运行。这是因为使用vector使分配动态化,而堆是存储大量数据的更好位置。

std::vector<bool> isprime(N);
std::vector<bool> zprime(N); 

更新代码

这是完全更新的代码!我也将ij设置为long long的值,所以您不必担心整数溢出,并且我使用了标准库sqrt函数来计算sqrt ofN。

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

typedef long long int ll;

constexpr long long N = 10000000; //Change N in this line
std::vector<bool> isprime(N);
std::vector<bool> zprime(N); 
vector<int> primes;
vector<int> zprimes;

void calcprime() {
    isprime[0] = false;
    isprime[1] = false;
    for (ll i = 2; i < N; i+=1) {
        isprime[i] = true;
    }
    for (ll i = 2; i < N; i+=1) {
        if (isprime[i]) {
            primes.push_back(i);
            for (ll j = 2; i*j < N; j+=1){
                isprime[i*j] = false;
            }
        }
    }
}
void zcalc(){
    ll sqrtN = sqrt(N); 
    for (ll i = 0; i <= sqrtN; i++) {
        for (ll j = 0; j <= sqrtN; j++) {
            ll q = (i*i)+(j*j);
            if ((q < N) && isprime[q] && !zprime[q]) {
                zprimes.push_back(q);
                zprime[q] = true;
            }
        }
    }
}
int main(){
   calcprime();
   zcalc();
   cout << zprimes.size();
   return 0;
}

答案 1 :(得分:2)

在您的代码中q的值可能超过N的值,并且在访问zprime[q]isprime[q]时可能导致分段错误。您要迭代ijsqrt(N),并为zprimeisprime分配了N个布尔值。 q的值可以从02N

ll q = (i*i)+(j*j);

您可以用

替换bool zprime[N] = {};bool isprime[N] = {};
bool zprime[N * 2 + 1] = {};

bool isprime[N * 2 + 1] = {};

分别。

该程序将不再存在段错误。或者,您可以在访问q < Nisprime[q]之前检查zprime[q]

此外,正如评论中已经指出的那样,(i*i)+(j*j)int。将该值分配给long long是没有用的。如果要防止溢出,请用((ll)i*i)+(j*j)替换它。

此外,对于大型数组,您应该更喜欢在堆上分配它。