符号付き100進法の計算方法を解説してみます 言語としてDelphiで説明します。 //まずは型:動的配列を符号付き8bit整数として取ります type s100 = array of Shortint; // 用意する関数はこの程度あればいいでしょう procedure s100Neg(var a:s100); //負数にする function s100Add(const a,b:s100):s100; function s100Sub(const a,b:s100):s100; function s100Mul(const a,b:s100):s100; function s100Div( x,y:s100;var b:s100):s100; //x /y の結果と余りがbで function s100Comp(var a,b:s100):integer; //比較結果が 符号で帰る function s100Power(const a,b:s100):s100; //べき乗 procedure s100Norm(var a:s100); // 整数正規化 procedure s100CyNorm(var a:s100;cy:Integer);//キャリーを収める function s100mulc(var a:s100;c:Integer):integer;//n倍して 溢れた桁 {////////// 負数////////// 配列aの 値は Σ a[i]*100^i です。 負数の表現は最上位だけ負数として残りは補数方式とします。  具体的には -100は [0,-1] -101は [-1,-1]ではなく[99,-2]とします -Σa[i]*100^i = Σ-a[i]*100^i つまり、負数にするには、単純に全部の桁を負数にします  それでも計算上問題無いのですが、補数表現にしておきましょう  補数というのは、上の桁から1借りて来る事です。100進なので  1借りれば下の桁では100足す事になります。  中間の桁では下に貸す1を引いて、99を足す事になります。  これを統一的にする為に、キャリに最初に1を持って  中間では99を足す事にします。 } procedure s100Neg(var a:s100); var i:integer; var carry:Integer; begin carry:=1; for i:=0 to High(a) do begin a[i]:=99-a[i]+carry;carry:=0; if a[i]>=100 then begin dec(a[i],100);inc(carry);end; end; s100CyNorm(a,carry); //最上位のキャリは後で始末します end; { /////// 整数加算 a+b ////////////////////////////// 加算はとても簡単です。正規化されていれば 両方の桁を 単純に足して、余り(100以上)があれば上の桁に足すだけです   ただし、途中片方の最上位が負数になっている可能性がありますから   中間加算結果であるcyも負数になる可能性があります。   ですから cy mod 100 も負数の可能性があります。   そこで再度100を足して mod 100を取ります   計算速度を上げるなら、短い方の配列までとそれ以後とを   分けるといいでしょう } function s100Add(const a,b:s100):s100; var i,cy:Integer; begin cy:=0; SetLength(Result,max(Length(a),Length(b))); //加算結果は大きい方の桁にあわす for i:=0 to High(Result) do begin if i>High(b) then inc(cy,a[i] ) //途中でbが終わったらaだけ else if i>High(a) then inc(cy, b[i] ) //途中でaが終わったらbだけ else inc(cy,a[i] +b[i]); //でなければ単純に足して Result[i]:=(100+(cy mod 100)) mod 100; cy:=(cy-Result[i]) div 100; end; s100CyNorm(Result,cy); end; {/////// 整数減算 a-b ///////////////// } function s100Sub(const a,b:s100):s100; var i,cy:Integer; begin cy:=0; SetLength(Result,max(Length(a),Length(b))); for i:=0 to High(Result) do begin if i>High(b) then inc(cy,a[i] ) else if i>High(a) then inc(cy, -b[i] ) else inc(cy,a[i] -b[i]); Result[i]:=(100+(cy mod 100)) mod 100; cy:=(cy-Result[i]) div 100; end; s100CyNorm(Result,cy); end; {///////////////////// 比較  比較は単純に引き算して符号を見てもいいのですが  それよりもっと簡単な方法があります。  正規化されてれば、桁数が同じなら  上位から引算して差がゼロ以外になった時の符号で見ればいい   桁数が違う場合は    その符号を見ます     ++なら 桁数差がそのまま符合結果に --なら-桁数差です +-なら無条件に+ -+なら無条件に- } function s100Comp(var a,b:s100):integer; var i:integer; begin s100Norm(a); s100Norm(b); Result:=High(a)-High(b); if Result=0 then for i:=High(a) downto 0 do begin Result:=a[i]-b[i]; if Result<>0 then exit; end else begin if a[High(a)]>=0 then begin if b[High(b)]<0 then Result:=1; end else begin if b[High(b)]>=0 then Result:=-1 else Result:=-1; end; end; end; { //////////// 掛算 ////////////////   掛算は筆算と同じ方法で行います a2 a1 a0 x b2 b1 b0 --------------- a2 a1 a0 x b0 a2 a1 a0 x b1 a2 a1 a0 x b2 ---------------------- 一番下の桁は a0xb0 一番上は a2xb2です 全体の桁数は aの桁数+bの桁数 -1 となります。 しかし、a2xb2の結果も桁上がりがありますから aの桁数+bの桁数を確保しておきます  一番下の桁から掛算を行います。 cy:=cy+Σa[ia]*b[ib]という計算をします i=ia+ib で ia:0〜high(a) ib:0〜high(b) という条件からiaの範囲計算をしています  桁上げは加算時は最大±1でしたが、  掛算の場合は大きくなります。でも処理は全く同じです  cyは32bitの整数ですからΣa[ia]*b[ib]の桁溢れ  については 20万桁(10進なら40万桁)まで大丈夫です  しかし、16bitで処理する場合は途中桁借りをする  必要がありますから注意して下さい } function s100Mul(const a,b:s100):s100; var i,ia,iaL,iaH:integer; var cy:integer; begin SetLength(Result,Length(a)+Length(b)); cy:=0; for i:=0 to High(Result) do begin iaL:=Max( 0,i-High(b)); iaH:=Min(High(a),i ); for ia:= iaL to iaH do cy:=cy+a[ia]*b[i-ia]; Result[i]:=(100+(cy mod 100)) mod 100; cy:=(cy-Result[i]) div 100; end; s100CyNorm(Result,cy); end; {///////べき //////////////////////////////  a^(b+c)=a^b*a^c という規則を使って  上位桁とその下とを分解しながら処理します } function s100mulc(var a:s100;c:Integer):integer; var i:integer; begin Result:=0; for i:=0 to High(a) do begin Result:=Result + a[i] * c; a[i] :=((Result mod 100)+100) mod 100; Result:=(Result - a[i]) div 100; end; end; function s100Power(const a,b:s100):s100; var cy:integer; var c:s100; begin cy:=b[High(b)] ; c:=copy(b,0,High(b)); if Length(b)>0 then Result:= s100Mul(s100Power(a,c),s100PowerC(a,cy*iPower(100,High(b)))) else Result:= s100PowerC(a,cy); end; ///////////////////////////////// { 除算の所で解説した割算です xをyで割る時、100^M > yとなるMから  1) a =x / 100^M  b=x-y*a : y*a+b=x と等号が成り立つ 2) da=b/ 100^M として a=a+da ; b=b-y*da; とすれば y*a+b=x と等号が保てる b = b- y; a = a+ 1; でもy*a+b=x でも、筆算法の方が早いかもしれません } function s100Div( x,y:s100;var b:s100):s100; var a,da:s100; begin if Length(x)=0 do begin b:=s100Sub(b,y); s100AddConst(a,1); end; Result:=a; end; //////////////////////////////////////////// // 整数正規化 procedure s100Norm(var a:s100); var i,cy:Integer; begin cy:=0; for i:=0 to High(a) do begin inc(cy,a[i]); a[i]:=(100+(cy mod 100)) mod 100; cy:=(cy-a[i]) div 100; end; s100CyNorm(a,cy); end; //////////////////////////////////////////// // 整数正規化(上位にcyを足すか 余分な桁を消す) procedure s100CyNorm(var a:s100;cy:Integer); begin if (Length(a)=0) and (cy=0) then begin SetLength(a,1);a[0]:=0; exit; end; if(cy >=0 ) then begin while cy >0 do begin SetLength(a , Length(a)+1); a[High(a)]:=cy mod 100; cy:=(cy- a[High(a)]) div 100; end; while (High(a)>0) and (a[High(a)]=0) do SetLength(a,Length(a)-1); end else begin while cy <-1 do begin SetLength(a,Length(a)+1); a[High(a)]:=100+(cy mod 100); cy:=(cy- a[High(a)]) div 100; end; while (High(a)>0) and (a[High(a)]=99) do SetLength(a,Length(a)-1); a[High(a)]:=a[High(a)]-100;//先頭だけ負数に end; { -----------メモ------------------------------------------ 掛算を高速化する方法 2桁の掛算として a1 a0 x b1 b0 ------------------- a1*b0 a0*b0 a1*b1 a0*b1 -------------------- の1の位を (a1+b0)*(a0+b1)-a0*b0-a1*b1とすれば1回掛算を節約出来るという 方法があります 2つに分解してはこの方法を再帰的に使えば 巨大桁の場合はそれなりの節約となりそうです。 C=(a1+a0)*(b1+b0),D=(a1-a0)*(b1-b0) と求めてから (C+D)/2-a0*b0 , (C-D)/2 , a0*b0 としても掛算は1回減りますが7回の加算が必要です 4桁の場合 (a3,a2,a1,a0) , (b3,b2,b1,b0) e0 = a0*b0 e1 = a1*b0+a0*b1 e2 = +a2*b0+a1*b1+a0*b2 e3 = a3*b0+a2*b1+a1*b2+a0*b3 e4 = a3*b1+a2*b2+a1*b3 e5 = a3*b2+a2*b3 e6 = a3*b3+ と16の掛算に分解できます c0= ( a0+a1+a2+a3 )*(b0+b1+b2+b3 ) c1= ( a0-a1-a2+a3 )*(b0-b1-b2+b3 ) c2= ( a0-a1+a2-a3 )*(b0-b1+b2-b3 ) c3= ( a0+a1-a2-a3 )*(b0+b1-b2-b3 ) を求め d0=( +c0 +c1 +c2 +c3 )/4 d1=( +c0 -c1 -c2 +c3 )/4 d2=( +c0 -c1 +c2 -c3 )/4 d3=( +c0 +c1 -c2 -c3 )/4 と計算すると d0 = a3*b3+a2*b2+a1*b1+a0*b0 d1 = a3*b2+a2*b3+a1*b0+a0*b1 d2 = a3*b1+a2*b0+a1*b3+a0*b2 d3 = a3*b0+a2*b1+a1*b2+a0*b3 が求められますこれを使えば e0 = a0*b0 e1 = a1*b0+a0*b1 e2 = +a2*b0+a1*b1+a0*b2 =d2 + a1*b1 - (a2*b0+a0*b2) e3 = a3*b0+a2*b1+a1*b2+a0*b3 =d3 e4 = a3*b1+a2*b2+a1*b3 =d2 + a2*b2 - (a2*b0+a0*b2) e5 = a3*b2+a2*b3 =d1 - e1 e6 = a3*b3+ =d0 - a1*b1-a2*b2-e0 となり、結局、4+5=9 回 16回の掛算が9回で済む事になります a'0= ( a0+a1+a2+a3 )  a'1= ( a0-a1-a2+a3 )  a'2= ( a0-a1+a2-a3 )  a'3= ( a0+a1-a2-a3 )  という変換が3回出て来ますが、これはコサイン変換です FFTアルゴリズムを使えば12回の加算を 8回に減らせられます g0=a0+a2 g1=a0-a2 g2=a1+a3 g3=a1-a3 a'0=g0+g2 a'1=g1-g3 a'2=g0-g2 a'3=g1+g3 -------------------------------------------------------- } end;