用Eratosthenes的方法超过50万

时间:2015-04-17 20:49:40

标签: c primes

我遇到了一个无法解决的问题

我想知道低于给定限制x的所有素数。允许我输入x并使用Erastosthenes的方法计算素数。在屏幕上显示结果并将其保存到文本文件中。

计算x下方的primenumbers,打印它们并将它们保存到文本文件中,我唯一的问题是x不能超过500000 你能帮助我吗?

#include <stdio.h>
#include <math.h>

void sieve(long x, int primes[]);

main()
{
    long i;
    long x=500000;
    int v[x];

    printf("give a x\n");
    scanf("%d",&x);

    FILE *fp;

    fp = fopen("primes.txt", "w");
    sieve(x, v);
    for (i=0;i<x;i++)
    {
        if (v[i] == 1)
        {
            printf("\n%d",i);
            fprintf(fp, "%d\n",i);
        }
    }
    fclose(fp);
}

void sieve(long x, int primes[])
{
    int i;
    int j;
    for (i=0;i<x;i++)
    {
        primes[i]=1; // we initialize the sieve list to all 1's (True)
        primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
    }
    for (i=2;i<sqrt(x);i++) // loop through all the numbers up to the sqrt(n)
    {
        for (j=i*i;j<x;j+=i) // mark off each factor of i by setting it to 0 (False)
        {
            primes[j] = 0;
        }
    }

}

4 个答案:

答案 0 :(得分:4)

通过声明char v [500000]而不是int v [100000],您将能够处理四倍的值。

通过声明unsigned char v [500000]并且每个素数只使用一个位,您可以处理八倍以上的值。这使得代码更复杂一些。

通过仅使用奇数筛子,您可以处理两倍的值。因为2是唯一的素数,所以没有必要将它们保留在筛子中。

由于函数中局部变量的内存通常非常有限,因此可以使用静态数组处理更多值。

答案 1 :(得分:1)

我相信你遇到的问题是如果堆栈中有超过500000个元素,则分配一个int数组。这不是一种有效的方法,使用一个数组,其中元素是数字,值表示它是否是素数。如果你想这样做,至少使用bool,而不是int,因为这应该只有1个字节,而不是4个。

另请注意这个

for (i=0;i<x;i++)
{
    primes[i]=1; // we initialize the sieve list to all 1's (True)
    primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}

您正在重新分配每个循环中的前两个元素。把它带出循环。

答案 2 :(得分:1)

您正在将x初始化为500000,然后创建一个包含x个元素的数组,因此它将具有500000个元素。然后你正在读x。当x的值发生变化时,数组不会改变大小 - 它固定为500000个元素,即创建数组时的x值。你想要这样的东西:

long x=500000;

printf("give a x\n");
scanf("%d",&x);

int *v = new int[x];

这可以修复固定大小的数组问题,并将其从堆栈中移出并进入堆,这样可以分配更多空间。它应该达到你可用内存的极限。

答案 3 :(得分:1)

v分配为int数组是浪费的,并且使其成为本地数组是有风险的,堆栈空间有限。如果数组变得足够大以超过可用的堆栈空间,程序将调用未定义的行为并可能崩溃。

虽然有办法通过将筛阵列更改为仅包含奇数或更少数字的位数组来提高筛子的效率(6n-1和6n + 1是一个很好的技巧),你仍然可以改进简单方法的效率提高了10倍,并且易于更改:

  • 在循环外修复primes[0]primes[1]

  • 清除prime的偏移,除了第一个和唯一的扫描奇数,

  • 对外循环限制使用整数运算,

  • 忽略已知为复合的数字,

  • 仅检查i的奇数倍。

以下是改进版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void sieve(long x, unsigned char primes[]) {
    long i, j;

    for (i = 0; i < x; i++) {
        primes[i] = i & 1;
    }
    primes[1] = 0;
    primes[2] = 1;
    /* loop through all odd numbers up to the sqrt(x) */
    for (i = 3; (j = i * i) < x; i += 2) {
        /* skip composite numbers */
        if (primes[i] == 0)
            continue;
        /* mark each odd multiple of i as composite */
        for (; j < x; j += i + i) {
            primes[j] = 0;
        }
    }
}

int main(int argc, char *argv[]) {
    long i, x, count;
    int do_count = 0;
    unsigned char *v;

    if (argc > 1) {
        x = strtol(argv[1], NULL, 0);
    } else {
        printf("enter x: ");
        if (scanf("%ld", &x) != 1)
            return 1;
    }

    if (x < 0) {
        x = -x;
        do_count = 1;
    }
    v = malloc(x);
    if (v == NULL) {
        printf("Not enough memory\n");
        return 1;
    }

    sieve(x, v);

    if (do_count) {
        for (count = i = 0; i < x; i++) {
            count += v[i];
        }
        printf("%ld\n", count);
    } else {
        for (i = 0; i < x; i++) {
            if (v[i] == 1) {
                printf("%ld\n", i);
            }
        }
    }
    free(v);
    return 0;
}