筛子或eratosthenes计算器 - 遇到内存问题并且数字崩溃> = 1,000,000

时间:2016-01-19 02:47:46

标签: c++ memory crash sieve-of-eratosthenes

我不确定为什么会这样。我尝试将变量更改为long long,我甚至尝试做了一些其他的事情 - 但是它或者是关于我的代码的低效率(它确实完成了查找所有素数到数字的整个过程,然后检查数字看看它是否可以被那个素数整除 - 非常低效,但它是我的第一次尝试,我觉得它完全可以完成....)

或者它溢出堆栈的事实。我不知道它究竟在哪里,但我所知道的是它必须与记忆和处理数字的方式有关。

如果我不得不猜测,我说当它正在处理到该数字的素数生成时会发生内存问题 - 即使我删除了对输入数字的检查,它就会死掉。

我会发布我的代码 - 只是要注意,我没有在很长一段时间内改回int,而且我还有一个未使用的SquareRoot变量,因为它应该尝试帮助内存效率但是我尝试这样做的方式并没有效果。我从来没有删除它。如果我能成功完成它,我会清理代码。

据我所知,它对于999,999非常可靠地工作并且下来,我实际上与其他相同类型的计算器进行了对比,它似乎确实产生了正确的答案。

如果有人可以帮助或解释我在这里搞砸了什么,那么你帮助一个人在没有任何学校或任何东西的情况下自己学习。所以它很感激。

#include <iostream>
#include <cmath>

void sieve(int ubound, int primes[]);

int main()
{
    long long n;
    int i;
    std::cout << "Input Number: ";
    std::cin >> n;

    if (n < 2) {
        return 1;
    }

    long long upperbound = n;
    int A[upperbound];
    int SquareRoot = sqrt(upperbound);
    sieve(upperbound, A);

    for (i = 0; i < upperbound; i++) {
        if (A[i] == 1 && upperbound % i == 0) {
            std::cout << " " << i << " ";
        }
    }
    return 0;
}

void sieve(int ubound, int primes[])
{
    long long i, j, m;

    for (i = 0; i < ubound; i++) {
        primes[i] = 1;
    }

    primes[0] = 0, primes[1] = 0;

    for (i = 2; i < ubound; i++) {
        for(j = i * i; j < ubound; j += i) {
            primes[j] = 0;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

如果您使用合法的C ++构造而不是非标准的variable length arrays,那么您的代码将会运行(无论是否产生正确的答案都是另一个问题)。

当您声明具有一百万或更多元素的数组时,问题很可能是超出了堆栈的限制。

因此,而不是:

long long upperbound = n;
A[upperbound];

使用std::vector

#include <vector>
//...
long long upperbound = n;
std::vector<int> A(upperbound);

然后:

sieve(upperbound, A.data());

std::vector不使用堆栈空间来分配其元素(除非您为其使用堆栈编写了一个分配器)。

事实上,您甚至不需要将upperbound传递给sieve,因为std::vector通过调用size()成员函数知道自己的大小。但我把它留作练习。

Live example using 2,000,000

答案 1 :(得分:0)

首先,阅读并应用PaulMcKenzie的建议。这是最重要的事情。我只是解决了你问题的一些问题仍未解决。

您似乎正在尝试将您误导性地称为upperbound的数字。这个数字的平方根的神秘作用与这个事实有关:如果数字是复合的 - 因此可以计算为某些素因子的乘积 - 那么这些素数因子中最小的不能大于正方形根数。事实上,只有一个因素可能更大,其他因素都不能超过平方根。

然而,就目前的形式而言,您的代码无法从这一事实中获益。现在的试验分组循环必须运行到number_to_be_factored / 2,以免错过任何因素,因为它的主体看起来像这样:

if (sieve[i] == 1 && number_to_be_factored % i == 0) {
   std::cout << " " << i << " ";
}

如果你稍微重构一下代码,你可以更有效地考虑因素:当你找到你的数字的最小素数因子p时,要找到的其余因子必须恰好是rest = number_to_be_factored / p(或{{ 1}},如果你愿意的话,其余的因素都不能小于p。但是,不要忘记p可能不止一次出现。

在任何一轮程序中,您只需要考虑p与当前数字的平方根之间的素因子;如果这些素数中没有一个除以当前数字那么它必须是素数。要测试p是否超过某个数字n的平方根,可以使用n = n / p,这在计算上实际计算平方根的效率更高。

因此,平方根有两种不同的角色:

  • 要考虑的数量的平方根限制了需要进行的筛分量
  • 在试验分割循环期间,当前数字的平方根给出了您需要考虑的最高素因子的上限

这是同一枚硬币的两面,但实际代码中有两种不同的用法。

注意:一旦您通过应用PaulMcKenzie的建议让您的代码正常工作,您也可以考虑在Code Review上发帖。