使用Atkin的Sieve计算素数之和低于200万

时间:2014-04-09 16:52:41

标签: c primes sieve-of-atkin

我正在做项目欧拉,我遇到了这个问题。我在VS 2013中运行代码,程序因溢出而崩溃。

这是我的方法:

void problem10()
{
    long long int iter = 2, sum = 0;

    //Sieve of Atkin
    bool isPrime[PRIME_LIMIT+1];

    for (long long int i = 5; i <= PRIME_LIMIT; i++)
    {
        isPrime[i] = false;
    }

    long long int lim = ceil(sqrt(PRIME_LIMIT));

    for (long long int x = 1; x <= lim; x++)
    {
        for (long long int y = 1; y <= lim; y++)
        {
            long long int n = 4 * x*x + y*y;
            if (n <= PRIME_LIMIT && (n % 12 == 1 || n % 12 == 5))
            {
                isPrime[n] = true;
            }

            n = 3 * x*x + y*y;
            if (n <= PRIME_LIMIT && (n % 12 == 7))
            {
                isPrime[n] = true;
            }

            n = 3 * x*x - y*y;
            if (x > y && n < PRIME_LIMIT && n % 12 == 11)
            {
                isPrime[n] = true;
            }
        }
    }

    // eliminate composites by seiving
    for (long long int n = 5; n <= lim; n++)
    {
        if (isPrime[n])
        {
            for (long long int k = n*n; k <= PRIME_LIMIT; k+= k*k)
            {
                isPrime[k] = false;
            }
        }
    }

    for (long long int n = 5; n <= PRIME_LIMIT; n++)
    {
        if (isPrime[n])
        {
            sum += n;
        }
    }
    sum = sum + 2 + 3;
    printf("%lld\n", sum);
    /* //A basic approach -- too slow
    while (iter < PRIME_LIMIT)
    {
        bool isDivisible = false;
        int prime = iter;
        for (int a = 2; a < iter; a++)
        {
            if (prime%a == 0)
            {
                isDivisible = true;
                break;
            }
        }

        if (isDivisible){}
        else
        {
            //printf("prime is: %d\n", prime);
            sum += prime;
        }
        iter++;
    }
    printf("Sum of prime is: %d\n", sum);
    */
}

此方法包括两种计算范围PRIME_LIMIT中所有素数之和的方法。第二种方法需要很长时间才能得到结果,并且可能需要一整天。第一种方法是使用Atkin筛,程序崩溃!

我的代码中有错误吗?请帮忙!

1 个答案:

答案 0 :(得分:2)

所以,让我们谈谈这个问题:

整数大小

与Java非常相似,C中的整数对它们可以容纳的大小有限制。在这里,您选择使用long long int。幸运的是,对于这个问题,总和将适合该数据类型。对于其他Project Euler问题,您需要使用BigInt类。

你的慢速方法

如果添加一个添加,那么缓慢的方法实际上很好。我们知道,我们需要搜索的除数列表实际上小于2 ... n中的所有数字。所以我们可以将你的一个循环更改为:

int max = ciel(sqrt(iter));
for (int a = 2; a < max; a++)
    if (prime % a == 0)
        isDivisible = true;
        break;

如果我们这样做,您的代码将相对较快地完成。

你的快速方法

我还没有完全通过这段代码,因为它看起来不像我记得的eratosthenes的筛子,但至少,你将用你的分配溢出堆栈。

#define PRIME_LIMIT 2000000
bool isPrime[PRIME_LIMIT+1];

让我们解决一下:

#define PRIME_LIMIT 2000000
static bool isPrime[PRIME_LIMIT+1]

或者:

#define PRIME_LIMIT 2000000
bool *isPrime = calloc(PRIME_LIMIT + 1, sizeof(bool));

推荐

我真的建议不要试图实现Atkin的Sieve。如果我要将其作为一个学习练习来实现,我会按此顺序执行:

  1. 你上面做的很慢的方法。在python中,类似的代码大约需要1分钟来解决问题。我怀疑C可以在大约10秒(或更快)的时间内完成。

  2. sieve of eratosthenes是一个更简单的实施筛子。我建议下次使用它。

  3. 然后尝试实施sieve of atkin。对于这种尺寸的问题,这种速度的算法完全没有必要。

相关问题