int getInt(struct NUMBER *a,int *x) { int i,j,tmp = 1,max = 0,min = 0; struct NUMBER b; *x = 0;//xに直す setInt(&b,INT_MAX);//2^31 - 1 = intで表される最高の数 max = (numComp(a,&b) == 1) ?0:1; setInt(&b,INT_MIN);//-2^31 = intで表される最少の数 min = (numComp(a,&b) == -1)?0:1; if(max&&min) { for(i = 0;i < KETA;i++) { for(j = 0;j < i;j++) tmp *= 10;//i乗になる *x = *x + (a->n[i] * tmp); tmp = 1; } } else if(!max) { *x = INT_MAX; return(-1); } else { *x = INT_MIN; return(-1); } *x *= getSign(a); 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); }
//減算 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 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 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 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; }
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); }
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); }
//除算(ひっ算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; }