int power(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int res = 0; struct NUMBER tmp_b,tmp_c,tmp; if(isZero(b) == 0)//bが最初から0ならば { setInt(c,1);//cを1に return(0);//n^0は(0を除いて)必ず1になるため } if(getSign(b) == -1)//bが負なら return(-1); copyNumber(b,&tmp_b);//bが破壊されないようにtmp_bに copyNumber(a,c);//aをcにコピー、cの初期値をaとする copyNumber(&tmp_b,&tmp);//tmp_bにtmpを代入、グダグダなのはわかってる。 decrement(&tmp,&tmp_b);//もうすでにcにはa^1があるので、1をまず引く while(1) { if(isZero(&tmp_b) == 0) break;//bが0になったら終了 copyNumber(c,&tmp_c);//tmp_cに現在のcの値を代入する res = multiple(a,&tmp_c,c); if(res == -1) break; copyNumber(&tmp_b,&tmp);//tmp_bにtmpを代入、グダグダなのはわかってる。 decrement(&tmp,&tmp_b);//tmp_b--;を実行してます } return(res); }
int factorial(bigNumber p) { /* computes the last digit od p! */ bigNumber pp, ppp; int result; /* first compute power of 2 */ result = computePowerOf2(p); /* now compute powers of 3, 7 and 9 */ copyNumber(pp, p); while(! isZero(pp)) { /* divide p by all cobinations of 2^i, 5^j */ copyNumber(ppp, pp); while(! isZero(ppp)) { result *= compute379(ppp); result %= 10; divide(ppp, 5); } divide(pp, 2); } return result; }
void swap(struct NUMBER *a,struct NUMBER *b) { struct NUMBER tmp;//一時保存用 copyNumber(a,&tmp);//tmp←a copyNumber(b,a);//a←b copyNumber(&tmp,b);//b←tmp }
void swap(struct NUMBER *a,struct NUMBER *b) { struct NUMBER temp; copyNumber(a,&temp); copyNumber(b,a); copyNumber(&temp,b); }
//乗算 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 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 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); }
int fastpower(struct NUMBER *a,struct NUMBER *b,struct NUMBER *c) { int res = 0,i = 0,mulKeta = KETA * 3.3 + 1; struct NUMBER tmp_b,tmp_c,one,two,tmp,surplus; struct NUMBER mul; setInt(&two,2);//twoは2という定数とする setInt(&one,1);//oneは1という定数とする copyNumber(b,&tmp_b);//tmp_bにbを代入 setInt(c,1);//cを1に if(isZero(b) == 0)//bが最初から0ならば return(0);//n^0は(0を除いて)必ず1になるためこれでOK if(getSign(b) == -1)//bが負なら return(-1); i = 0; while(1) { copyNumber(&tmp_b,&tmp);//tmpにtmp_bを代入 divide(&tmp,&two,&tmp_b,&surplus);//tmp_b /= 2,surplus = tmp_b % 2をおこなう if(i == 0) copyNumber(a,&mul); else { copyNumber(&mul,&tmp); res = multiple(&tmp,&tmp,&mul);//mul ^ i = mul ^ i/2^2 } if(res == -1) return(-1);//multipleで何か起きた場合、異常終了 if(numComp(&surplus,&one) == 0)//余り = 1だったら { copyNumber(c,&tmp_c); res = multiple(&tmp_c,&mul,c);//c *= mul[i] } if(res == -1) return(-1); i++; if(isZero(&tmp_b) == 0) break;//tmp_bが0になったらbreak } return(0);//ここまで正常にできれば成功 }
int computePowerOf2(bigNumber a) { /*computes the last digit of power of two involved in resul */ int power = 0; bigNumber p1; if(a[0] == 1 && a[1] == 1) return 1; copyNumber(p1, a); while (!isZero(p1)) { divide(p1, 2); power = (power + mod4(p1)) % 4; } copyNumber(p1, a); while (!isZero(p1)) { divide(p1, 5); power =(power - mod4(p1) + 4)%4; } return power2[power]; }
int addNumber(Number *res, const Number r1, const Number r2) { int k = 0; k = r1.end_pos - r2.end_pos ; if ( k >= DIGIT_LEN) { copyNumber (res, r1, r2); return k; } if ( k <= -DIGIT_LEN) { copyNumber(res, r2,r1); return k; } /* k is a number that has not DIGIT_LEN or -DIGIT_LEN */ return k; }
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); }
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 compute379(bigNumber p) { /* computes the last digit of product of all numbers smaller then p and ending in 3, 7 a 9 */ bigNumber p1; int r, poc, result; copyNumber(p1, p); r = divide(p1, 10); poc = mod4(p1); result = (power3[poc] * power7[poc] * power9[poc]) % 10; if (r >= 3) result *= 3; if (r >= 7) result *= 7; if (r >= 9) result *= 9; return result % 10; }
//ウォリス積の計算 //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; }
int main(void) { srandom(time(NULL)); struct NUMBER a,b,c,d,e; int r; int x=0,y=0,z=0; int i,flag; //setint のテスト setInt(&a,-12344); printf("a = "); dispNumber(&a); printf("\n"); //setSignのテスト copyNumber(&a,&b); setSign(&b,1); printf("b = "); dispNumber(&b); printf("\n"); //getSignのテスト r=getSign(&b); printf("getSign() = %d\n",r); //numCompのテスト r=numComp(&a,&b); printf("numComp() = %d\n",r); setInt(&b,-9996702); printf("b = "); dispNumber(&b); printf("\n"); //addのテストプログラム add(&b,&a,&c); printf("add = "); dispNumber(&c); printf("\n"); //subのテストプログラム sub(&c,&a,&d); printf("sub = "); dispNumber(&d); printf("\n"); setInt(&a,12345); setInt(&b,67894); //multipleのテスト multiple(&b,&a,&d); printf("mul = "); dispNumber(&d); printf("\n"); setInt(&a,INT_MIN); printf("a = "); dispNumber(&a); printf("\n"); putchar('\n'); 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; }
void getAbs(struct NUMBER *a,struct NUMBER *b) { copyNumber(a,b); setSign(b,1); }
void getAbs(struct NUMBER *a,struct NUMBER *b) { int i; copyNumber(a,b); setSign(b,1);//signをプラスにする }
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); }