//乗算 int multiple(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c){ int i=0; int j; int k; int h=0;//桁上がりの値を一時保管 int e;//e=aj+bj+h int C;//C+=d[i] int f;//外のfor文で使う int ak,bk,tk; struct NUMBER d; struct NUMBER dtemp,ctemp; clearByZero(c); clearByZero(&d); ak=readKETA(a); bk=readKETA(b); tk=ak+bk; if(tk>KETA) return -1; if(ak==0 || bk==0){ setInt(c,0); return 0; } for(i=KETA-1;i>=KETA-tk;i--){ //for(i=0;i<tk;i++){ h=0; clearByZero(&d); for(j=KETA-1;j>=KETA-tk;j--){ e=a->n[j]*b->n[i]+h; //e=a->n[j]*b->n[KETA-1-i]+h; d.n[j]=e%10; h=e/10; if(i==0 && h!=0){ //if(i==tk && h!=0){ return -1; } } for(k=0;k<KETA-1-i;k++){ clearByZero(&dtemp); if(mulBy10(&d,&dtemp)==-1) return -1; copyNumber(&dtemp,&d); } //for(k=KETA-1;k>=KETA-tk;k--){ clearByZero(&ctemp); if(add(c,&d,&ctemp)==-1) return -1; copyNumber(&ctemp,c); //} } return 0; }
int sub(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int i,h=0,d=0; struct NUMBER temp; clearByZero(&temp); clearByZero(c); if(getSign(a)==1) { if(getSign(b)==1) { for(i=0;i<KETA;i++) { if(numComp(a,b)==1) { d=a->n[i]-b->n[i]-h; h=0; if(d<0) { d+=10; h=1; } c->n[i]=d; } else { getAbs(b,&temp); sub(&temp,a,c); setSign(c,-1); } } } else if(getSign(b)==-1) { getAbs(b,&temp); add(a,&temp,c); } } else if(getSign(a)==-1) { if(getSign(b)==1) { getAbs(a,&temp); add(b,&temp,c); setSign(c,-1); } else if(getSign(b)==-1) { getAbs(b,&temp); add(&temp,a,c); } } return 0; }
//減算 int sub(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c){ int h=0;//桁下がりみてる int i; int cha,chb;//構造体が正か負か確認引数 int flag; struct NUMBER d;//絶対値をとる struct NUMBER e,f;//大小比較するためのe>f clearByZero(c); clearByZero(&e); clearByZero(&f); if(numComp(a,b)==1){ //大きいほうをe小さいほうをf copyNumber(a,&e); copyNumber(b,&f); setSign(c,1); } if(numComp(a,b)==-1){ //上に同じく copyNumber(b,&e); copyNumber(a,&f); setSign(c,-1); } if(numComp(a,b)==0){ setInt(c,0); setSign(c,1); return 1; } for(i=KETA-1;i>-1;i--){ e.n[i]=e.n[i]-h; //aiからhを引く if(e.n[i] >= f.n[i]){//ai>=biならば c->n[i]=e.n[i]-f.n[i];//ci=ai-bi h=0;//h=0 } if(e.n[i] < f.n[i]){//ai<biならば c->n[i]=10+e.n[i]-f.n[i];//ci=10+ai-bi h=1;//h=1 } } if(h != 0){ printf("/erroe\n"); return -1; } return 0; }
int multiple(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int i,j,h=0,tempb,tempa,e; struct NUMBER d,mai1,mai2,temp; clearByZero(&d); clearByZero(c); if(getSign(a)==1) { if(getSign(b)==1) { for(i=0;i<KETA-1;i++) { h=0; clearByZero(&d); tempb=b->n[i]; for(j=0;j<KETA;j++) { tempa=a->n[j]; e=tempa*tempb + h; if(j+i<KETA) d.n[j+i]=e%10; h=e/10; } copyNumber(c,&temp); add(&temp,&d,c); } } else if(getSign(b)==-1) { getAbs(b,&mai1); multiple(a,&mai1,c); setSign(c,-1); } } else if(getSign(a)==-1) { if(getSign(b)==1) { getAbs(a,&mai1); multiple(b,&mai1,c); setSign(c,-1); } else if(getSign(b)==-1) { getAbs(a,&mai1); getAbs(b,&mai2); multiple(&mai1,&mai2,c); } } }
int add(struct NUMBER *a,struct NUMBER *b, struct NUMBER *c) { int i,e=0,d=0; int flag=0; struct NUMBER temp,temp2; clearByZero(&temp); clearByZero(&temp2); clearByZero(c); if(getSign(a)==1) { if(getSign(b)==1) { for(i=0;i<KETA;i++) { d=a->n[i]+b->n[i]+e; if(i==KETA-1 && d>=10) { printf("OverFlow\n"); clearByZero(c); flag=1; break; } c->n[i]=d%10; e=d/10; } } else if(getSign(b)==-1) { getAbs(b,&temp); sub(a,&temp,c); } } else { if(getSign(b)==1){ getAbs(a,&temp); sub(b,&temp,c); } else if(getSign(b)==-1) { getAbs(a,&temp); getAbs(b,&temp2); add(&temp,&temp2,c); setSign(c,-1); } } return flag; }
//多倍長変数の加算 int add(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c){ int i; int D; int E=0; int cha,chb; int flag=0; struct NUMBER d,e; clearByZero(c); for(i=KETA-1;i>-1;i--){ D=a->n[i]+b->n[i]+E; c->n[i]=D%10; E=D/10; } if(E != 0){ printf("/erroe\n"); return -1; } return 0; }
int sub(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int i,f_hizero = 0,h = 0,res = 0,tmp = 1; struct NUMBER tmp_a,tmp_b; /*値を動かすので一時的に保存*/ copyNumber(a,&tmp_a); copyNumber(b,&tmp_b); if(numComp(a,b) == -1) { copyNumber(a,&tmp_b); copyNumber(b,&tmp_a);//a > bにしたいので tmp = -1; } else { copyNumber(a,&tmp_a); copyNumber(b,&tmp_b); } clearByZero(c);//cを0に if(getSign(a) == 1&&getSign(b) == 1)//a,bも+の時は通常のsub { if(numComp(&tmp_a,&tmp_b) == 0) return(0);//aとbが同じならcは0だから f_hizero = firstNotZero(&tmp_a);//aは必ず大きい値なのでf_hizeroも大きい方になる /*計算部*/ for(i = 0;i <= f_hizero;i++) { tmp_a.n[i] -= h;//繰り下がり分を引く h = (tmp_a.n[i]>=tmp_b.n[i])? 0:1; c->n[i] = h * 10 + tmp_a.n[i] - tmp_b.n[i]; } if(f_hizero == KETA - 1&&h != 0) res = -1; setSign(c,tmp); } /*絶対値を使うので保存*/ getAbs(a,&tmp_a); getAbs(b,&tmp_b); if(getSign(a) == 1 && getSign(b) == -1)//aが+、bが-の時はa+b通常のadd res = add(a,&tmp_b,c); if(getSign(a) == -1 && getSign(b) == 1 )//aが-、bが+の時は-a-b、つまり-(a+b)、addの結果を負にする { res = add(b,&tmp_a,c); setSign(c,-1); } if(getSign(a) == -1 && getSign(b) == -1)//aもbも-の時は-a + b、つまりb-aをすればいい。 res = sub(&tmp_b,&tmp_a,c); return(res); }
void copyNumber(struct NUMBER *a,struct NUMBER *b) { int i; clearByZero(b);//一応0クリア for(i = 0;i < KETA;i++)//最大桁までiを大きくする b->n[i] = a->n[i]; setSign(b,getSign(a)); }
int divBy10(struct NUMBER *a,struct NUMBER *b) { int i,flag=0; flag=a->n[0]; clearByZero(b); for(i=0;i<KETA-1;i++) b->n[i]=a->n[i+1]; return flag; }
int divBy10(struct NUMBER *a,struct NUMBER *b) { int i,f_hizero = firstNotZero(a),res = 0; clearByZero(b);//0で初期化する res = a->n[0];//最下位桁の値がそのままあまりになるので for(i = 0;i < f_hizero;i++)//bにi + 1が含まれるのを考慮してi = 1 b->n[i] = a->n[i + 1];//a[i + 1]の値を変更するのでf_hizero未満でiを動かす setSign(b,getSign(a));//aとbの符号をそろえる return(res); }
int mulBy10(struct NUMBER *a,struct NUMBER*b) { int i,flag=0; clearByZero(b); if(a->n[KETA-1]!=0) flag=-1; else for(i=KETA-1;i>0;i--) { b->n[i]=a->n[i-1]; } return flag; }
//int型変数のセット void setInt(struct NUMBER *a,int x){ int amari; int i; clearByZero(a); for(i=KETA-1;i>0;i--){ amari=x%10; a->n[i]=amari; x=(x-amari)/10; } }
int mulBy10(struct NUMBER *a,struct NUMBER *b) { int i,f_hizero = firstNotZero(a),res = 0; clearByZero(b);//0で初期化する if(f_hizero == KETA - 1)//最初の非ゼロが最高桁なら res = -1;//フローがある else if(f_hizero == 0)//最初の非ゼロが最低桁(0)なら res = -1;//十倍しても意味がない(アンダーフロー…?) for(i = 0;i <= f_hizero;i++)//最高位の非ゼロまで b->n[i + 1] = a->n[i];//a[i]をb[i + 1]にうつす = 10倍 setSign(b,getSign(a));//aとbの符号をそろえる return(res); }
int arctan(struct NUMBER *a,struct NUMBER *b) { struct NUMBER i,tmp1,tmp2; struct NUMBER apow,tenpow,mone,n;//計算に使う変数 int j,res; clearByZero(b); clearByZero(&i); clearByZero(&tmp1); clearByZero(&tmp2); clearByZero(&apow); clearByZero(&tenpow); setInt(&n,1); tenpow.n[KETA-1] = 1;//tenpowは10^(KETA-1) j = 0; while(1) { res = fastpower(a,&n,&apow);//apow = a^n if(res != 0) break; res = multiple(&n,&apow,&tmp1);//tmp1 = n * apow if(res != 0) break; res = divide(&tenpow,&tmp1,&tmp2,&apow);//tmp2 = tenpow/tmp1,apowは使わないからこれ以降使わないから if(res != 0) break; if(i.n[0]%2)//iが奇数なら,手っ取り早く偶奇を見たいからこう setSign(&tmp2,-1); else //iが偶数なら setSign(&tmp2,1); copyNumber(b,&tmp1); add(&tmp1,&tmp2,b);//b += (1/n * 1/(a^n)) * 10^(KETA-1),オーバーフローなどはないので戻り値は保存しない if(firstNotZero(&tmp2) <= KETA/10)//(1/i * 1/(a^i)) * 10^(KETA-1)がKETAの1/10程度になったら break; /*2i +1の操作*/ copyNumber(&i,&tmp1);//i → tmp increment(&tmp1,&i);//i++ copyNumber(&i,&tmp1);//i → tmp1 add(&tmp1,&i,&n);//n = 2i(n= i + i) copyNumber(&n,&tmp1);//i → tmp increment(&tmp1,&n);//i++ } return(res); }
//多倍長変数のコピー void copyNumber(struct NUMBER *c,struct NUMBER *d){ int i; int x; int ck; clearByZero(d); ck=readKETA(c); d->sign = c->sign; for(i=0;i<KETA-ck;i++){ d->n[i]=0; } for(i=KETA-ck;i<KETA;i++){ d->n[i]=c->n[i]; } }
int add(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int d = 0,e = 0,f_hizero = 0,i,res = 0; struct NUMBER abs_a,abs_b; /*絶対値を使う可能性があるので保存*/ getAbs(a,&abs_a); getAbs(b,&abs_b); clearByZero(c); f_hizero = (firstNotZero(a)>firstNotZero(b))?firstNotZero(a):firstNotZero(b); //f_hizeroは最初の非ゼロが現れる場所が高い方の非ゼロの場所を格納 /*計算部*/ if(getSign(a) == 1&&getSign(b) == 1)//a,bも+の時は通常のadd { for(i = 0;i <= f_hizero + 1&&i <= KETA - 1;i++) //桁上りがある場合があるのでf_hizero + 1まで、またf_hizero == KETA-1の時はKETA-1まで { d = a->n[i] + b->n[i] + e; c->n[i] = d%10; e = d / 10; } if(f_hizero == KETA - 1&&e != 0) res = -1; } if(getSign(a) == 1 && getSign(b) == -1)//aが+、bが-の時はa-b通常のsub res = sub(a,&abs_b,c); if(getSign(a) == -1 && getSign(b) == 1)//aが-、bが+の時は-a+b、つまりb-a、aとbが逆になったsub res = sub(b,&abs_a,c); if(getSign(a) == -1 && getSign(b) == -1)//aもbも-の時は-(a+b)、つまりaddの結果を負にする { res = add(&abs_a,&abs_b,c); setSign(c,-1);//cを-にする } return(res); }
int setInt(struct NUMBER *a,int x) { int i; clearByZero(a); if(x<0) { setSign(a,-1); x=x*(-1); } else if(x>0) setSign(a,1); else setSign(a,0); for(i=0;i<KETA;i++) { a->n[i]=x%10; x=x/10; if(x<1) break; } }
//ウォリス積の計算 //PI=4*n^2/4*n^2-1(n=1からn=kまで) int main(int argc,char **argv) { struct NUMBER num;//ウォリス積のn struct NUMBER four;//4倍するための4 struct NUMBER store;//n^2 struct NUMBER bunbo; struct NUMBER bunsi; struct NUMBER store4;//4倍したstore struct NUMBER store4_1;//4*n^2-1の計算結果を保管 struct NUMBER two;//2倍するためのもの struct NUMBER bunsix2;//2倍した値保存 struct NUMBER sho;//割り算した商 struct NUMBER amari;//わり算したあまり struct NUMBER numtemp;//numをインクリメントした値を格納する struct NUMBER hundred; struct NUMBER bunsix10; struct NUMBER dispKETA; struct NUMBER tmp; int i;//for文 int n=1; int kt;//円周率の表示 time_t start,end; start=time(NULL); srandom(time(NULL)); setInt(&four,4); setInt(&two,2); /* multiple(&four,&two,&hundred); dispNumber(&hundred); return 0; */ setInt(&hundred,100); setInt(&bunbo,1); setInt(&bunsi,1); while(n<=woris){ printf("ループ回数 %d回\n",n); setInt(&num,n);//多倍長にnをセットする if(multiple(&num,&num,&store)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1;//n^2する } if(multiple(&store,&four,&store4)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1;//4*n^2を計算 } if(decrement(&store4,&store4_1)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1;//4*n^2-1を計算 } copyNumber(&bunsi,&tmp);//tmpに分子コピー if(multiple(&tmp,&store4,&bunsi)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1;//分子と4*n^2かけ、分子に格納 } copyNumber(&bunbo,&tmp);//tmpに分母コピー if(multiple(&tmp,&store4_1,&bunbo)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1;//分母と4*n^2_1かけて分母に格納 } n++; } printf("\n"); printf("分子:"); dispNumber(&bunsi); printf("\n"); if(multiple(&bunsi,&two,&bunsix2)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1; } printf("分子x2:"); dispNumber(&bunsix2); printf("\n"); i=0; clearByZero(&tmp); while(i<disp_kt){ if(mulBy10(&bunsix2,&tmp)==-1) { printf("オーバーフローです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1; } i++; copyNumber(&tmp,&bunsix2); } copyNumber(&bunsix2,&bunsix10); printf("分子x10:"); dispNumber(&bunsix10); printf("\n"); printf("分母:"); dispNumber(&bunbo); printf("\n"); if(divide(&bunsix10,&bunbo,&sho,&amari)==-1) { printf("エラーです\n"); end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return -1; } printf("\n"); printf("商"); dispNumber(&sho); printf("\n"); /* printf("あまり"); dispNumber(&amari); printf("\n"); printf("分子x10の桁数:%d\n",readKETA(&bunsix10)); */ end=time(NULL); printf("time=%d[s]\n",(int)(end-start)); return 0; }
//除算(ひっ算ver.) int divide(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c,struct NUMBER *d){ struct NUMBER az,bz;//絶対値 struct NUMBER bb;//azと同じ桁数にしたbzを保管 struct NUMBER sho,amari; struct NUMBER tmp;//一時保管場所 struct NUMBER n;//n:azのコピー struct NUMBER c1,d1;//普通の除算を行うときに使う struct NUMBER bz2;//bzコピー int i=0; int ak,bk;//aとbのゼロ判定かつ桁数をみる。 int f;//aとbの桁数の差 int ch; clearByZero(c); clearByZero(d); clearByZero(&az); clearByZero(&bz); clearByZero(&bb); clearByZero(&sho); clearByZero(&amari); clearByZero(&tmp); clearByZero(&n); copyNumber(a,&az); copyNumber(b,&bz); copyNumber(&bz,&bz2); if(numComp(a,b)==-1) { return -1; } if(isZero(b)==0){ return -1; } if(isZero(a)==0){ setInt(c,0); setInt(d,0); return 0; } ak=readKETA(a); bk=readKETA(b); //bをaと桁数合わせる。 if(ak>bk){ f=ak-bk; //桁数の差を知る while(i<f){ mulBy10(&bz,&bb); copyNumber(&bb,&bz); i++; } } copyNumber(&bz,&bb); //除算実行 while(1){ //桁数を合わせたbのほうが大きい場合 //÷10して、fをデクリメント if(numComp(&az,&bb)==-1){ divBy10(&bb,&tmp); copyNumber(&tmp,&bb); f--; } //分母のほうが大きい場合 if(numComp(&az,&bz2)==-1) { break; } copyNumber(&az,&n); i=0; while(numComp(&az,&bb)==1 || numComp(&az,&bb)==0){ //az<bbになるまで繰り返す。 //ふつうの割り算アルゴリズム sub(&n,&bb,&tmp); copyNumber(&tmp,&n); copyNumber(&n,&az); i++; } c->n[KETA-1-f]=i; copyNumber(&n,&az); } copyNumber(&n,d); return 0; }
int multiple(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int e,h,res = 0,i,j,f_hizero_a,f_hizero_b; struct NUMBER d,tmp_c,abs_a,abs_b,tmp; clearByZero(c); clearByZero(&tmp_c); /*絶対値を使う場合があるので*/ getAbs(a,&abs_a); getAbs(b,&abs_b); if(isZero(a) == 0 || isZero(b) == 0) return(0);//もうcは0になっているのでcBZはしない setInt(&tmp,1);//tmpに1を代入 if(numComp(a,&tmp) == 0)//aとtmpが同じ値なら = aが1なら { copyNumber(b,c);//cにbをコピー return(0); } if(numComp(b,&tmp) == 0) { copyNumber(a,c);//cにaをコピー return(0); } f_hizero_a = firstNotZero(a);//aの最初の非ゼロを数える、これはjの最大値となる f_hizero_b = firstNotZero(b);//bの最初の非ゼロを数える、これはiの最大値となる if(getSign(a) == 1&&getSign(b) == 1)//a,bも+の時は通常のmultiple { for(i = 0;i <= f_hizero_b;i++)//第一ループ、求めるのはa * b { h = 0; clearByZero(&d); if(b->n[i] == 0)//a * bのbが0の時の結果は0 clearByZero(&d); else if(b->n[i] == 1)//a * bのbが1の時の結果はa { for(j = 0;j <= f_hizero_a;j++) { d.n[j + i] = a->n[j]; } } else { for(j = 0;j <= f_hizero_a;j++)//第二ループ、求めるのはa * b_i { if(i + j >KETA - 1)//i + jは値を代入する部分なのでここがKETA - 1を超えていたらアウト return(-1); e = a->n[j] * b->n[i] + h;//eにa_j * b_iと前の繰り上がりを足す d.n[j + i] =e % 10;//d_i+jにeの一桁目を代入 h = e / 10;//hにeの二桁目を代入 = 繰り上がり } } if(i + j < KETA) d.n[j + i] = h;//jがf_hizero_aまでなので乗算した時のhをここに代入する。 else if(h != 0) return(-1); res = add(c,&d,&tmp_c); if(res == -1)//addでオーバーフローが起きた時のためのif return(-1); copyNumber(&tmp_c,c); } } if(getSign(a) == 1 && getSign(b) == -1)//aが+、bが-の時は-(a*|b|) { res = multiple(a,&abs_b,c); setSign(c,-1); } if(getSign(a) == -1 && getSign(b) == 1 )//aが-、bが+の時は-(|a|*b) { res = multiple(&abs_a,b,c); setSign(c,-1); } if(getSign(a) == -1 && getSign(b) == -1)//aもbも-の時は|a| * |b| res = multiple(&abs_b,&abs_a,c); return(res); }
int divide(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c,struct NUMBER *d) { int k,res = 0; struct NUMBER tmp_a,n,m,l,abs_a,abs_b; copyNumber(a,&tmp_a);//aが破壊されないようにtmp_aにコピー if(isZero(b) == 0)//isZeroは0か-1が返るので return(-1); clearByZero(c); clearByZero(d);//c,dを0でクリア clearByZero(&n); clearByZero(&m); clearByZero(&l);//作業用変数n,m,lを0でクリア setInt(&n,1);//適当な変数に1を突っ込む if(numComp(b,&n) == 0)//除数が1ならば { copyNumber(a,c);//c = a; return(0); } getAbs(a,&abs_a); getAbs(b,&abs_b);//a,bの絶対値をとる if((getSign(a) == 1) && (getSign(b) == 1)) { while(1)//xから何回yを引けるか調べる { if(numComp(&tmp_a,b) == -1)//a < bならば break; copyNumber(b,&n);//bを作業用変数nに代入 setInt(&m,1);//作業用変数mに1を代入 while(1) { copyNumber(&n,&l); mulBy10(&l,&n); copyNumber(&m,&l); mulBy10(&l,&m);//mとnを10倍 if(numComp(&tmp_a,&n) == -1)//a < nならば { copyNumber(&n,&l); divBy10(&l,&n); copyNumber(&m,&l); divBy10(&l,&m);//10倍しちゃったので10で割る。いい方法を模索中、一時的に保存する? break; } } while(1) { copyNumber(&tmp_a,&l);//lに現在のaを代入 sub(&l,&n,&tmp_a);//a = l -n; すなわち a -= n; copyNumber(c,&l);//lにcを代入 add(&l,&m,c);//c = l + m;すわなち c += m; if(numComp(&tmp_a,&n) == -1) break; } } copyNumber(&tmp_a,d);//残ったtmp_aがすなわち剰余 } if((getSign(a) == 1) && (getSign(b) == -1)) { res = divide(a,&abs_b,c,d); setSign(c,-1);//+ / -は解が負であるため } if((getSign(a) == -1) && (getSign(b) == 1)) { res = divide(&abs_a,b,c,d); setSign(c,-1);//- / +は解が負であるため setSign(d,-1);//- / +は剰余が負であるため } if((getSign(a) == -1)&& (getSign(b) == -1)) { res = divide(&abs_a,&abs_b,c,d);//-x / -yは解が正であるためなにもしない setSign(d,-1);//- / -は剰余が負であるため } return(res); }