关于如何让这个程序工作n = 1万亿(除了升级/购买新计算机)之外的任何建议?
错误如下:构建后,正在执行的程序(弹出命令行样式输出窗口)然后快速关闭,我收到以下错误" ProjectPrimes.exe已停止工作(Windows正在寻找这个问题的解决方案。"我怀疑这与内存问题有关,因为我第一次遇到n = 2000万,但那是在我选择malloc / free' sieve&#39之前;数组(即,我的筛选数组是维度nx 1的大数组,每个元素由1或0组成)。
该程序需要大约35秒才能完成前3亿个整数(16,252,325个素数),所以没关系,但没什么了不起的。正如我所提到的,目标是能够产生低于1万亿的质数,所以还有很长的路要走......
如果相关,这是我的机器规格(如果在这台机器上目标恰好是不合理的):2.40ghz i5,4GB RAM,64位Windows 7。
方法概述,对于那些不熟悉的人:我们使用Sienda of Sundaram方法。没有进入证明,我们首先消除一个整数以下的所有奇数非素数" n"使用筛选函数:[2 *(i + j + 2 * i * j)+1 | i< - [1..n / 2],j< - [i..an优化上限]]。然后我们交掉偶数(当然不包括两个)。这让我们留下了素数。
为什么prime函数返回(指向包含数组的指针)n下面的完整素数集?那么,目标是能够识别(i)n以下的素数以及(ii)列出n以下的素数。这也是为什么我选择将n以下的素数计数作为参数传递的原因。
这里不那么令人兴奋的主要'功能:
int main() {
long ceiling = 300*1000*1000;
long *numPrimes;
long *primes;
primes = primesToSS(ceiling+1, numPrimes);
printf("\n\nThere are %d primes below %d.\n\n",*numPrimes,ceiling);
free(primes);
return 0;
}
这就是肉:
//n represents the ceiling, i.e., the integer below which we will generate primes
//cnt* is a pointer which will point the number of primes below n
long* primesToSS( long n, long* cnt ) {
//initialize sieve by setting all elements equal to 1 (except for 0 and 1)
long *sieve = malloc(n*sizeof(long));
initArray(sieve, n, 1);
sieve[0] = 0; sieve[1] = 0;
//eliminate all odd composite numbers
for (int i = 1; i <= n/2; ++i)
for (int j = i; j <= (n-2*i)/(2*(2*i+1)); ++j)
sieve[ 2*(i+j+2*i*j)+1 ] = 0;
//eliminate all even numbers greater than two
//and count total number of primes below n
long numPrimes = 1;
for (int i = 3; i < n; ++i) {
if (i % 2 == 0) sieve[i] = 0;
numPrimes += sieve[i];
}
*cnt = numPrimes;
//create array of primes
long *primes = malloc(numPrimes*sizeof(int));
long counter = 0;
for (int i = 0; i < n; ++i) {
if (sieve[i] == 1) {
primes[counter] = i;
counter++; }
}
free(sieve);
return primes;
}
void initArray( int* arr, int len, int n ) {
for( int i = 0; i < len; ++i) arr[i] = n; }
答案 0 :(得分:5)
让我们做一些观察:
以16个数字/字节打包数字(你应该做的最基本的设置),你需要~58 GiB的RAM。但是,没有必要为整个范围分配。只需分配几亿到几十亿的较小范围(尝试改变最高性能的数量),最多可以转化为几百MiB,然后使用不到100万的素数列表筛选范围。
此步骤可以并行完成 - 您只需要共享少于100万的素数列表。
顺便说一句,这种技术称为分段筛。
答案 1 :(得分:3)
long *numPrimes;
...
primes = primesToSS(ceiling+1, numPrimes);
printf("\n\nThere are %d primes below %d.\n\n",*numPrimes,ceiling);
正如Blastfurnace所说,你正在解除引用(并存储通过)一个未初始化的指针。这应该是
long numPrimes;
...
primes = primesToSS(ceiling+1, &numPrimes);
printf("\n\nThere are %d primes below %d.\n\n", numPrimes, ceiling);
可能还有其他错误......特别是没有检查malloc失败。哦,这是一个:
long *sieve;
initArray(sieve, n, 1);
...
void initArray( int* arr, int len, int n ) {
for( int i = 0; i < len; ++i) arr[i] = n; }
int
和long
是不同的类型。在这里,你再次这样做:
long *primes = malloc(numPrimes*sizeof(int));
最佳做法是使用sizeof元素,而不是类型,这可以避免这种情况:
long *primes = malloc(numPrimes * sizeof *primes);
检查代码是否存在其他明显错误。
样式注释:将}放在一行的末尾是不好的做法,并在以后添加另一行时请求错误。
答案 2 :(得分:2)
一些内存注意事项:对于前1万亿个素数,如果用一个比特代表每个数字,则需要1万亿/ 8个字节。那是125000000000 = 119209 MB = 116 GB的RAM。
虽然您可以要求您的操作系统创建一个200GB的SWAP分区,但性能可能会很差。如果您想保持相同的算法,那么您需要查看memory mapped files。
那仍然会很慢,但至少你可以分配一个足够大的数组。
接下来的步骤将是查看不同的素数算法,或者您需要研究内存压缩算法。在您的情况下,sparse matrices将无效,因为您的起始矩阵全部为1,并且您最终删除了几乎所有元素。