下面的代码打印出[m,n]之间的所有素数。
当我使用unsigned int时,malloc在我的64位系统上正常工作直到10^9
。
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#define true 1
#define false 0
void SieveOfEratosthenes(unsigned int m ,unsigned int n) {
bool *prime;
prime = (bool*)malloc(m - n + 2);
if (!prime) {
printf("FAIL\n");
return;
}
memset(prime, true, (m - n + 2));
unsigned int i = 2;
for (i = 2; i * i <= n; i++) {
if (prime[i] == true) {
for (unsigned int j = i * 2; j <= n; j += i)
prime[j] = false;
}
}
for (i = m; i <= n; i++)
if (prime[i] && i != 1)
printf("%u \n", i);
}
int main() {
clock_t begin,end;
unsigned int m, n;
scanf("%u %u", &m, &n);
begin = clock();
SieveOfEratosthenes(m, n);
end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("\nTime Taken : %lf secs\n", time_spent);
return 0;
}
但是当我从unsigned int
更改为unsigned long long
时,对于更大的值,malloc
对每个值都会失败,即使对于小值也是如此。为什么这不起作用?
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#define true 1
#define false 0
void SieveOfEratosthenes(unsigned long long m, unsigned long long n) {
bool *prime;
prime = (bool*)malloc(m - n + 2);
if (!prime) {
printf("FAIL\n");
return;
}
memset(prime, true, (m - n + 2));
unsigned long long i = 2;
for (i = 2; i * i <= n; i++) {
if (prime[i] == true) {
for (unsigned long long j = i * 2; j <= n; j += i)
prime[j] = false;
}
}
for (i = m; i <= n; i++)
if (prime[i] && i != 1)
printf("%llu \n", i);
}
int main() {
clock_t begin,end;
unsigned long long m, n;
scanf("%llu %llu", &m, &n);
begin = clock();
SieveOfEratosthenes(m,n);
end = clock();
double time_spent=(double)(end - begin) / CLOCKS_PER_SEC;
printf("\nTime Taken : %lf secs\n", time_spent);
return 0;
}
答案 0 :(得分:3)
您的代码因此而具有未定义的行为:
unsigned int m, n;
scanf("%llu %llu", &m, &n);
此外,您没有分配适当的内存量:
prime = (bool*)malloc(m - n + 2);
如果m
小于n + 2
,则大小变得很大。它只适用于unsigned int
,因为您可以在系统上分配4GB或16GB的内存。
事实上,根据您的算法,您必须分配n + 1
元素,因为您在筛子期间使用从2开始的数字索引此数组。
此外,对于此数组,您应该使用unsigned char
而不是bool
,因为类型bool
可能大于1个字节。
以下是修改后的版本:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void SieveOfEratosthenes(unsigned long long m, unsigned long long n) {
unsigned char *prime = malloc(n + 1);
if (!prime) {
printf("FAIL\n");
return;
}
memset(prime, 1, n + 1);
unsigned long long i, j;
for (i = 2; i * i <= n; i++) {
if (prime[i]) {
for (j = i * 2; j <= n; j += i)
prime[j] = 0;
}
}
for (i = m; i <= n; i++) {
if (prime[i] && i != 1)
printf("%llu\n", i);
}
}
int main() {
clock_t begin, end;
unsigned long long int m, n;
if (scanf("%llu %llu", &m, &n) == 2) {
begin = clock();
SieveOfEratosthenes(m, n);
end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("\nTime Taken : %f secs\n", time_spent);
}
return 0;
}
可以对主要候选者和筛子切片使用单独的数组,对于非常大的数量的切片是必要的。尝试为大小为ceil(sqrt(n + 1))
的主要候选者分配一个数组并对其进行筛分,而不是为切片分配一个数组,并使用正确的偏移和初始值对其进行筛分,使用第一个的素数阵列。
这是一个天真的实现:
void SieveOfEratosthenes(unsigned long long m, unsigned long long n) {
unsigned int maxp = (unsigned int)(ceil(sqrt(n)) + 1);
unsigned char *composite = calloc(maxp, 1);
unsigned char *slice = calloc(n - m + 1, 1);
if (!composite || !slice) {
free(composite);
free(slice);
printf("FAIL\n");
return;
}
/* compute the primes */
unsigned int p, q;
for (p = 2; p * p < maxp; p++) {
if (!composite[p]) {
for (q = p * 2; q < maxp; q += p)
composite[p] = 1;
}
}
/* sieve the slice */
unsigned long long i;
if (m == 0)
slice[0] = 1;
if (m <= 1 && n >= 1)
slice[1 - m] = 1;
for (p = 2; p < maxp; p++) {
if (!composite[p]) {
i = 2 * p;
if (i < m) {
i = m - m % p;
if (i < m)
i += p;
}
while (i <= n) {
slice[i - m] = 1;
i += p;
}
}
}
for (i = m; i <= n; i++) {
if (!slice[i - m])
printf("%llu\n", i);
}
free(composite);
free(slice);
}