我已经在C中实现了一个spigot算法,但是,当要计算的小数位数太高时,会出现segfaults(SIGSEGV)。错误发生的位数在我拥有的几台不同的Windows计算机上略有不同,但它发生在156210左右。我只会给出相关的代码,但老实说我真的不明白错误,所以我会给你我的完整代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int held[20]; //I wont have 19 consecutive 9's in pi, right?
int held_length = sizeof(held)/sizeof(int);
FILE *f;
void releaseDigits() {
int c;
for(c = held_length-1; c >= 0; c--) {
if(held[c] != -1) {
//printf("release: %i\n", held[c]); //debugging output
fprintf(f, "%i", held[c]);
}
}
}
void incHeld() {
int c;
for(c = held_length-1; c >= 0; c--) {
if(held[c] != -1) {
held[c]++;
}
}
}
void blankHeld() {
int c;
for(c = held_length-1; c >= 0; c--) {
held[c] = -1;
}
/*for(c = 0; c < held_length; c++) {
printf("BLANK_%i:%i\n", c, held[c]);
}*/ //debugging output
}
void deleteLast() {
int c = held_length-1;
while(held[c] != -1) {
c--;
}
held[c+1] = -1;
}
void holdDigit(int hold) {
int c = held_length-1;
while(held[c] != -1) {
c--;
}
held[c] = hold;
for(c = 0; c < held_length; c++) {
//printf("held_%i:%i\n", c, held[c]); //debugging output
}
}
void main() {
time_t start, end;
int n; //decimals of pi, 156207 max if printf, 156210 if fprintf, higher = sivsegv
printf("Decimal places of pi to calculate (max 156210 for now): ");
scanf("%i", &n);
start = clock();
f = fopen("pi.txt", "w"); //open file
if (f == NULL) {
printf("Error opening file!\n");
exit(1);
}
n++; //overcompensate for odd ending digit error
//initial array of 2,2,2,...2
int rem[((10*n)/3)+2]; //sizeof(one)/sizeof(int);
int init_count;
for(init_count = 0; init_count < ((10*n)/3)+2; init_count++) {
rem[init_count] = 2;
}
//main digit loop
int carry;
int decimal;
int pi_digit;
for(decimal = 0; decimal <= n; decimal++) {
carry = 0;
int sum;
int i;
for(i = (10*n)/3 + 1; i >= 1; i--) {
sum = (rem[i]*10)+carry;
rem[i] = sum % ((2*i)+1);
carry = ((sum-rem[i])/((2*i)+1))* i;
//printf("decimal:%i i:%i B:%i carry:%i sum:%i rem:%i\n", decimal, i, (2*i)+1, carry, sum, rem[i]); //debugging output
}
sum = (rem[0]*10)+carry;
rem[0] = sum % 10;
pi_digit = (sum - rem[0])/10;
//printf("sum:%i rem:%i\n",sum, rem[i]); //debugging output
if(pi_digit != 10) {
if(pi_digit != 9) {
if(decimal > 0) {
releaseDigits();
}
if(decimal == 1) {
fprintf(f, "."); //shove a point up in that shit
}
blankHeld();
holdDigit(pi_digit);
}
else {
holdDigit(pi_digit);
}
}
else {
incHeld();
releaseDigits();
blankHeld();
holdDigit(0);
}
printf("\r%i/%i decimal places done... ", decimal-1, n-1);
}
deleteLast(); //hide overcompensation
releaseDigits();
fclose(f);
end = clock();
int raw_seconds = (end - start)/1000.;
int seconds = raw_seconds % 60;
int minutes = (raw_seconds - seconds)/60;
printf("\n\nSuccessfully calculated %i decimal places of pi in %i minutes and %i seconds!\nSaved to pi.txt\nPress ENTER to exit the program.\n", n-1, minutes, seconds);
while(getch()!=0x0d);
}
这里发生了什么?
答案 0 :(得分:2)
我在你的代码上使用了着名的内存检查工具Valgrind。相对较小的值(即10,100,1000,甚至10000)都没有问题。尝试156210立即让Valgrind抱怨。看起来这个问题始于这一行:
int rem[((10*n)/3)+2];
问题是以这种方式分配存储要求来自堆栈的内存和此计算值((10 * 156210/3 + 2)= 520702,sizeof(int)= 4在Windows上,所以520702 * 4 = about 2MB)远远超过机器准备从堆栈中提供的。
如果你需要这么多内存,最好使用malloc()从堆中分配它(之后不要忘记free())。