long long int让我的Eratosthenes筛子超级慢?

Ash*_*pta 3 c performance sieve sieve-of-eratosthenes

我有一个程序,要求我找到素数直到10**10-1 (10,000,000,000).我写了一个Eratosthenes筛子来做这件事,它的效果很好(而且准确)高达10**9 (1,000,000,000).我通过计算它找到的素数来确认它的准确性,它在这里找到的图表上与 50,847,534的值相匹配.我用作unsigned int存储类型,它在大约30秒内成功找到所有素数.

但是,10**10要求我使用更大的存储类型:long long int.一旦我切换到这个,程序运行速度明显变慢(它已经3小时加上它仍在工作).这是相关代码:

typedef unsigned long long ul_long;
typedef unsigned int u_int;

ul_long max = 10000000000;                            
u_int blocks = 1250000000;
char memField[1250000000];     

char mapBit(char place) {             //convert 0->0x80, 1->0x40, 2->0x20, and so on
    return 0x80 >> (place);
}

for (u_int i = 2; i*i < max; i++) {

    if (memField[i / 8] & activeBit) {               //Use correct memory block
        for (ul_long n = 2 * i; n < max; n += i) {
            char secondaryBit = mapBit(n % 8);       //Determine bit position of n
            u_int activeByte = n / 8;                //Determine correct memory block
            if (n < 8) {                             //Manual override memory block and bit for first block
                secondaryBit = mapBit(n);
                activeByte = 0;
            }
            memField[activeByte] &= ~(secondaryBit);  //Set the flag to false
        }
    }
    activeBit = activeBit >> 1;                       //Check the next
    if (activeBit == 0x00) activeBit = 0x80;
} 
Run Code Online (Sandbox Code Playgroud)

我认为,因为10**10它大10**910倍,所以它应该花费10倍的时间.这个缺陷在哪里?为什么更改long long导致如此重大的性能问题以及如何解决此问题?我认识到数字会变大,所以它应该稍慢一点,但只是到最后.有什么我想念的东西.

注意:我意识到在long int 技术上应该足够大 但我的limits.h说即使我正在编译64位也不行.这就是为什么我使用long long int万一有人想知道.另外,请记住,我没有计算机科学培训,只是一个业余爱好者.

编辑:只需在"发布"中将其作为x86-64运行,并提供一些调试语句.我得到以下输出:

在此输入图像描述

看起来我打了u_int绑定.我不知道为什么i会这么大.

chq*_*lie 12

你的程序有一个无限循环for (u_int i = 2; i*i < max; i++).i是unsigned int如此i*i包裹在32位和总是小于max.做i一个ul_long.

请注意,对于位0到7,应使用从1到0x80的更简单的位模式.

这是一个完整的版本:

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

typedef unsigned long long ul_long;
typedef unsigned int u_int;

#define TESTBIT(a, bit)   (a[(bit) / 8] & (1 << ((bit) & 7)))
#define CLEARBIT(a, bit)  (a[(bit) / 8] &= ~(1 << ((bit) & 7)))

ul_long count_primes(ul_long max) {
    size_t blocks = (max + 7) / 8;
    unsigned char *memField = malloc(blocks);
    if (memField == NULL) {
        printf("cannot allocate memory for %llu bytes\n",
               (unsigned long long)blocks);
        return 0;
    }
    memset(memField, 255, blocks);
    CLEARBIT(memField, 0);  // 0 is not prime
    CLEARBIT(memField, 1);  // 1 is not prime
    // clear bits after max
    for (ul_long i = max + 1; i < blocks * 8ULL; i++) {
        CLEARBIT(memField, i);
    }

    for (ul_long i = 2; i * i < max; i++) {
        if (TESTBIT(memField, i)) {           //Check if i is prime
            for (ul_long n = 2 * i; n < max; n += i) {
                CLEARBIT(memField, n);                   //Reset all multiples of i
            }
        }
    }
    unsigned int bitCount[256];
    for (int i = 0; i < 256; i++) {
        bitCount[i] = (((i >> 0) & 1) + ((i >> 1) & 1) +
                       ((i >> 2) & 1) + ((i >> 3) & 1) +
                       ((i >> 4) & 1) + ((i >> 5) & 1) +
                       ((i >> 6) & 1) + ((i >> 7) & 1));
    }
    ul_long count = 0;
    for (size_t i = 0; i < blocks; i++) {
        count += bitCount[memField[i]];
    }
    printf("count of primes up to %llu: %llu\n", max, count);
    free(memField);
    return count;
}

int main(int argc, char *argv[]) {
    if (argc > 1) {
        for (int i = 1; i < argc; i++) {
            count_primes(strtoull(argv[i], NULL, 0));
        }
    } else {
        count_primes(10000000000);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

对于10 ^ 10,它在10秒内完成10秒9和131秒:

count of primes up to 1000000000: 50847534
count of primes up to 10000000000: 455052511
Run Code Online (Sandbox Code Playgroud)