贴一个比较完整的:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int M,N;
int starty;
int *x,*y;
void init_N()
{
double n=M*8;
double nn;
do{
nn=n;
n=(log(10)*M*8+nn)/log(nn);
}while(fabs(nn-n)>=0.1);
N=(int)n+1;
}
void init(){//initialize y=x to 0.5
int i;
x=(int *)malloc(sizeof(int)*M);
y=(int *)malloc(sizeof(int)*M);
if(x==NULL||y==NULL){
printf("Out of memory\n");
exit(-2);
}
x[ 0 ]=50000000;
for(i=1;i<M;i++)x[ i ]=0;
for(i=0;i<M;i++)y[ i ]=x[ i ];
init_N();
}
#ifdef _WIN32
typedef __int64 longlong;
#else
typedef long long longlong;
#endif
void step(int k){
//divide y by k
int i;
longlong c=0;
for(i=starty;i<M;i++){
longlong u=c*100000000+y[ i ];
y[ i ]=(int)(u/k);
c=(int)(u%k);
}
while(y[starty]==0&&starty<M)starty++;
//Add x by y
c=0;
for(i=M-1;i>=starty;i--){
int u=x[ i ]+y[ i ]+c;
if(u>=100000000){
c=1;u-=100000000;
}else c=0;
x[ i ]=u;
}
while(c&&x[i]==99999999){x[i]==0;i--;}
if(c)x[i]++;
}
int main(int argc, char *argv[]){
int i,realM;
if(argc>=2){
M=atoi(argv[1]);
if(M<=1)return -1;
}else{
printf("Please input number of digits of e to be calculated:\n");
if(scanf("%d\n",&M)!=1||M<=1)
return -1;
}
realM=M;
M=(M+7)/8+1;
init();
for(i=3;i<=N;i++){
step(i);
}
printf("2.");
if(x[M-1]>=50000000){
for(i=M-2;x[i]==99999999&&i>=0;i--){
x[i]=0;
}
x[i]++;
}
for(i=0;i<realM/8;i++)printf("%08d",x[ i ]);
if(realM%8>0){
int left=realM%8;
int m=1,j;
for(j=0;j<8-left;j++)m*=10;
printf("%0*d",left,(x[i]+m/2)/m);
}
printf("\n");
}
先把我的代码变成:
for(k=3;k<N;k++){
c[0]=0;
for(i=0;i<M;i++){
int u=c[ i ]*10000+y[ i ];
y[ i ]=u/k;
c[ i+1 ]=u%k;
}
//Add x by y
d[ i ]=0;
for(i=M-1;i>=0;i--){
int u=x[ i ]+y[ i ]+d[ i ];
d[ i+1 ]=u/10000;
x[ i ]=u%10000;
}
}
然后改变代码的执行顺序,要让k变成内循环先执行。为此,需要先将两个for(i的循环合并,
为此,我们需要将两个for(i=...)的循环都要变成i递减的循环。
但是由于第一个循环中有跨循环的数据依赖关系(Loop-carried data dependence),我们无法直接交换
所以对循环还要采取线性变换,就是那种可以将矩形变成平行四边行方式的变换。
在这里,它的代码还使用了一个特性,也就是1/k!的计算中,对于比较大的k,算出来的数字很小,所以前面会有很多0,所以计算前面的位数时,我们不需要累加的1/N!,而只要比较小的就可以了,而它的程序是表明,对于计算道第4k位(10进制位),只要计算道1/(14k)!就可以了。
计算到一万位
#define M (10000/4)
#define N 3250 // 3250*(log(3250)-log(e))>10000, so 3250!<10^10000
int x[M],y[M];
void init(){//initialize y=x to 0.5
int i;
x[ 0 ]=5000;
for(i=1;i<M;i++)x[ i ]=0;
for(i=0;i<M;i++)y[ i ]=x[ i ];
}
void step(int k){
//divide y by k
int i;
unsigned c=0;
for(i=0;i<M;i++){
int u=c*10000+y[ i ];
y[ i ]=u/k;
c=u%k;
}
//Add x by y
c=0;
for(i=N-1;i>=0;i--){
int u=x[ i ]+y[ i ]+c;
if(u>=10000){
c=1;u-=10000;
}else c=0;
x[ i ]=u;
}
}
int main(){
int i;
init();
for(i=3;i<=N;i++){
step(i);
}
printf("2.");
for(i=0;i<M;i++)printf("%04d",x[ i ]);
printf("\n");
}