嗯,SO和其他论坛都有很多这样的问题。但是,这些都没有帮助。
我在" C"查找范围内的素数。我在long int中的范围。我正在使用Sieve of Eratosthenes"算法。我正在使用一长串整数来存储从1到极限的所有数字。如果不使用数组,我想不出更好的方法。代码工作正常,直到10000000.但在那之后,它耗尽内存并退出。以下是我的代码。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef unsigned long uint_32;
int main() {
uint_32 i, N, *list, cross=0, j=4, k, primes_cnt = 0;
clock_t start, end;
double exec_time;
system("cls");
printf("Enter N\n");
scanf("%lu", &N);
list = (uint_32 *) malloc( (N+1) * sizeof(uint_32));
start = clock();
for(i=0; i<=N+1; i++) {
list[i] = i;
}
for(i=0; cross<=N/2; i++) {
if(i == 0)
cross = 2;
else if(i == 1)
cross = 3;
else {
for(j=cross+1; j<=N; j++) {
if(list[j] != 0){
cross = list[j];
break;
}
}
}
for(k=cross*2; k<=N; k+=cross) {
if(k <= N)
list[k] = 0;
}
}
for(i=2; i<=N; i++) {
if(list[i] == 0)
continue;
else
primes_cnt++;
}
printf("%lu", primes_cnt);
end = clock();
exec_time = (double) (end-start);
printf("\n%f", exec_time);
return 0;
}
我陷入困境,无法想出更好的方法来实现这一目标。任何帮助将非常感激。感谢。
修改
我的目标是生成并打印低于该范围的所有素数。由于打印耗费了大量时间,我想到了第一步。
答案 0 :(得分:2)
还有其他算法不需要您生成高达N的素数来计算低于N的素数。最简单的算法是勒让德素数计数。该算法要求您仅生成sqrt(N)素数以确定N以下的素数。
算法背后的想法是
pi(n) = phi(n, sqrt(n)) + pi(sqrt(n)) - 1
where
pi(n) = number of prime below N
phi(n, m) = number of number below N that is not divisible by any prime below m.
平均值phi(n,sqrt(n))= sqrt(n)到n之间的素数。有关如何计算phi,您可以转到以下链接(Feasible implementation of a Prime Counting Function)
它更有效的原因是因为计算phi(n,m)比计算pi(n)最容易。假设我想计算phi(100,3)表示低于或等于100的数字不能被2和3整除。您可以执行以下操作。 phi(100,3)= 100 - 100/2 - 100/3 + 100/6。
答案 1 :(得分:1)
您的代码使用的内存大约是其所需内存的32倍。请注意,自您初始化list[i] = i
以来,作业cross = list[j]
可以替换为cross = j
,因此可以使用位向量替换list
。
然而,这还不足以使范围达到2 64 ,因为你的实现需要2个 61 字节(2 exbibytes)的内存,所以你需要优化一些。
接下来需要注意的是,当&#34;穿越&#34;时,您不需要前往N/2
。数字:√N就足够了(你应该能够通过考虑将合数除以高于√N的除数的结果来证明这一点)。这会带来您可以达到的内存要求,因为您可以通过&#34;穿越&#34;素数将适合大约4 GB的内存。
一旦你有一个交叉素数阵列,你就可以为任何范围构建一个部分筛,而不会在它之前保留所有范围内的所有范围。这称为分段筛。您可以在primesieve生成器的页面上找到有关它的详细信息以及一个简单的实现。这种方法的另一个优点是你可以将它并行化,从而进一步缩短时间。
答案 2 :(得分:1)
您可以稍微调整算法以计算块中的素数。
加载数组的一部分(尽可能多地适合内存),另外还要保存所有已知素数的列表。
每当你加载一个块时,首先通过已知的素数,并且类似于常规筛,设置所有非素数。
然后,再次检查数组,标记所有可能的数据,并将列出的新素数添加到列表中。
完成后,您将拥有一个包含所有素数的列表。
答案 3 :(得分:0)
我可以看到你正在使用的方法是 Eratosthenes 的基本实现,它首先显示所有2个多重,然后是3个多重,依此类推。
但我有一个更好的解决方案。实际上,关于spoj PRINT存在疑问。请仔细阅读并检查后面的约束。以下是此问题的代码段:
#include<stdio.h>
#include<math.h>
#include<cstdlib>
int num[46500] = {0},prime[5000],prime_index = -1;
int main() {
/* First, calculate the prime up-to the sqrt(N) (preferably greater than, but near to
sqrt(N) */
prime[++prime_index] = 2; int i,j,k;
for(i=3; i<216; i += 2) {
if(num[i] == 0) {
prime[++prime_index] = i;
for(j = i*i, k = 2*i; j<=46500; j += k) {
num[j] = 1;
}
}
}
for(; i<=46500; i+= 2) {
if(num[i] == 0) {
prime[++prime_index] = i;
}
}
int t; // Stands for number of test cases
scanf("%i",&t);
while(t--) {
bool arr[1000005] = {0}; int m,n,j,k;
scanf("%i%i",&m,&n);
if(m == 1)
m++;
if(m == 2 && m <= n) {
printf("2\n");
}
int sqt = sqrt(n) + 1;
for(i=0; i<=prime_index; i++) {
if(prime[i] > sqt) {
sqt = i;
break;
}
}
for(; m<=n && m <= prime[prime_index]; m++) {
if(m&1 && num[m] == 0) {
printf("%i\n",m);
}
}
if(m%2 == 0) {
m++;
}
for(i=1; i<=sqt; i++) {
j = (m%prime[i]) ? (m + prime[i] - m%prime[i]) : (m);
for(k=j; k<=n; k += prime[i]) {
arr[k-m] = 1;
}
}
for(i=0; i<=n-m; i += 2) {
if(!arr[i]) {
printf("%i\n",m+i);
}
}
printf("\n");
}
return 0;
}
我希望你明白这一点:
而且,正如你所提到的那样,你的程序在10 ^ 7之间工作正常,但是在它失败之后,它必定是因为你必须耗尽内存。
注意:我只是出于知识目的而共享我的代码。请不要复制并粘贴它,直到你明白为止。