我正在尝试在C中构建素筛,这样做时,我遇到了0除法错误。这对我来说很奇怪,因为我要除以质数(当然不能为0)。
我设法将问题追溯到以下代码段(注意顶部和底部调试打印):
int *comb(int primes[], int start, int end) {
for (int i = 1;i<primes[0];i++) {
printf("primes[%d] = %d\n", i, primes[i]);
}
// Initialize check-list
int *numbers = malloc(sizeof(int)*(end - start));
for (int i = start;i < end;i++) {
numbers[i - start] = i;
}
for (int i = 1;i<primes[0];i++) {
printf("primes[%d] = %d\n", i, primes[i]);
}
}
当然,打印语句应该给出完全相同的输出,但是从primes[10]
开始,它们是完全不同的。实际上,此列表应包含从0到100的所有素数,现在它给出输出:
primes[1] = 2
primes[2] = 3
primes[3] = 5
primes[4] = 7
primes[5] = 11
primes[6] = 13
primes[7] = 17
primes[8] = 19
primes[9] = 23
primes[10] = 39617
primes[11] = 0
primes[12] = 100
primes[13] = 101
primes[14] = 102
primes[15] = 103
primes[16] = 104
primes[17] = 105
primes[18] = 106
primes[19] = 107
primes[20] = 108
primes[21] = 109
primes[22] = 110
primes[23] = 111
primes[24] = 112
primes[25] = 113
对我来说很明显,这意味着我的numbers[]
数组正在以某种方式覆盖我的primes[]
数组。
什么可能导致这种奇怪的行为,我该如何阻止它发生?
编辑:我设法解决此问题的最小示例是:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
int *Sieve(int n) {
int found_primes = 0;
// Initialize prime array
int *prime = malloc(sizeof(int) * n);
for (int i = 0;i < n;i++) {
prime[i] = i;
}
// Start sieving
for (int i = 2;i < n;i++) {
// If i isn't sieved out, print it and discard its multiples
if (prime[i] != 0) {
found_primes++;
for (int j = 2 * i;j < n;j += i) { // Discard multiples.
prime[j] = 0;
}
}
}
printf("We found %d primes in step 1:\n", found_primes);
int *prime_list = malloc(found_primes + 1);
prime_list[0] = found_primes + 1; // Add length information to array.
// Fill prime_list
int counter = 1; // Skip length element
for (int i = 2;i < n;i++) {
if (prime[i] != 0) {
prime_list[counter++] = prime[i];
}
}
return prime_list;
}
int *comb(int primes[], int start, int end) {
for (int i = 1;i<primes[0];i++) {
printf("primes[%d] = %d\n", i, primes[i]);
}
// Initialize check-list
int *numbers = malloc(sizeof(int)*(end - start));
for (int i = start;i < end;i++) {
numbers[i - start] = i;
}
for (int i = 1;i<primes[0];i++) {
printf("primes[%d] = %d\n", i, primes[i]);
}
// Comb out the non-primes
for (int i = 1;i < primes[0];i++) {
// x*primes[i] - start --> needs to be positive
printf("Start: %d\n primes[%d]: %d\n", start, i, primes[i]);
double j_start = ceil(start / primes[i]) * primes[i];
for (int j = j_start; j < end;j += primes[i]) {
numbers[j - start] = 0;
}
}
// Count primes
int found_primes = 0;
for (int i = 0;i < end - start;i++) {
if (numbers[i] != 0) {
found_primes++;
}
}
printf("We found %d primes in step 2.\n", found_primes);
// Fill prime_list
int *prime_list = malloc(found_primes + 1);
prime_list[0] = found_primes + 1; // Add length information to array.
int counter = 1; // Skip length information
for (int i = 0;i < end - start;i++) {
if (numbers[i] != 0) {
prime_list[counter++] = numbers[i];
}
}
return prime_list;
}
int main() {
// Initialize program with user input
int max_number = 10000;
// Calculate all needed prime numbers.
int sqrtn = floor(sqrt(max_number));
int *prime_list = Sieve(sqrtn+1);
int *primes = comb(prime_list, sqrtn, max_number);
return 0;
}