以前投稿した多桁(多倍長)ルーチンの「除算」ができました。
動作検証のため、先の分数計算を行いました。
!定数
DECLARE EXTERNAL NUMERIC MultiPrecision.RADIX, MultiPrecision.L2
DECLARE EXTERNAL NUMERIC MultiPrecision.c0(), MultiPrecision.c1()
!演算
DECLARE EXTERNAL FUNCTION MultiPrecision.lNum2Str$, MultiPrecision.lcomp
DECLARE EXTERNAL SUB MultiPrecision.lStr2Num, MultiPrecision.lcopy
DECLARE EXTERNAL SUB MultiPrecision.ladd, MultiPrecision.lsub
DECLARE EXTERNAL SUB MultiPrecision.lmul, MultiPrecision.ldiv
DECLARE EXTERNAL SUB MultiPrecision.llmul, MultiPrecision.ldivqr
!----------------------------------------
!Σ[k=1,n]1/k の計算
LET t0=TIME
DIM P(0 TO L2),Q(0 TO L2)
CALL lStr2Num("0",P) !t=P/Q=1
CALL lStr2Num("1",Q)
DIM T1(0 TO L2),T2(0 TO L2)
FOR k=1 TO 1129
CALL lmul(P,k, T1) !t=t+1/k=(P*k+Q)/(Q*k) 通分
CALL ladd(T1,Q, P)
CALL lmul(Q,k, T2)
CALL lcopy(T2,Q)
NEXT k
PRINT lNum2Str$(P)
PRINT lNum2Str$(Q)
DIM A(0 TO L2),B(0 TO L2)
CALL lcopy(P,A) !LET A=P !copy it
CALL lcopy(Q,B) !LET B=Q
LET c=0 !繰り返し回数 debug
DO UNTIL lcomp(B,c0)=0 !最大公約数を求める
LET c=c+1 !debug
CALL ldivqr(A,B, T1,T2) !LET R=MOD(A,B) !MOD(x,y)=x-y*INT(x/y)
CALL lcopy(B,A) !LET A=B
CALL lcopy(T2,B) !LET B=R
LOOP
PRINT "c=";c !debug
PRINT "gcd=";lNum2Str$(A) !PRINT "gcd=";A !debug
CALL ldivqr(P,A, T1,T2) !LET P=P/A !約分
CALL lcopy(T1,P)
CALL ldivqr(Q,A, T1,T2) !LET Q=Q/A
CALL lcopy(T1,Q)
PRINT "P=";lNum2Str$(P) !PRINT "P=";P !結果の表示
PRINT "Q=";lNum2Str$(Q) !PRINT "Q=";Q
PRINT TIME-t0
END
MODULE MultiPrecision !正の多桁(多倍長)整数の計算
!桁の数字の列を格納する配列a()を考える。
!上位桁 下位桁
!a(L2),a(L2-1),…,a(1),a(0) の構造で表すことができる。
!言い換えると、n進数表記の各桁がa()となる。
!たとえば、100進数とすると、a(k)は正の整数2桁(0~99)となる。
!例. 12345は1*100*100+23*100+45だから、a(2)=1、a(1)=23、a(0)=45。
SHARE NUMERIC KETA
PUBLIC NUMERIC RADIX,L2
LET KETA=4 !桁数 1,2,3,4 ※32bitか64bit整数の範囲
LET RADIX=10^KETA !基数
LET L=3000 !求める桁数 ※
LET L2=INT(L/KETA)+1 !配列の大きさ
PUBLIC NUMERIC c0(0 TO 1000) !※
CALL lStr2Num("0",c0) !定数0
PUBLIC NUMERIC c1(0 TO 1000) !※
CALL lStr2Num("1",c1) !定数1
SHARE NUMERIC aa(0 TO 1000),bb(0 TO 1000),m(0 TO 1000) !作業用 ※
!----- 下位の演算ルーチン
PUBLIC SUB ladd
EXTERNAL SUB ladd(a(),b(), c()) !多桁+多桁 ※C=A+B
LET cy=0 !桁上がり
FOR i=0 TO L2 !下の桁から
LET d=a(i)+b(i)+cy !同じ桁で
IF d<RADIX THEN
LET c(i)=d
LET cy=0
ELSE
LET c(i)=d-RADIX
LET cy=1 !上の桁へ
END IF
NEXT i
IF cy>0 THEN
PRINT "加算オーバーフロー"
STOP
END IF
END SUB
PUBLIC SUB lsub
EXTERNAL SUB lsub(a(),b(), c()) !多桁-多桁 ※A>B、C=A-B
LET brrw=0 !借り
FOR i=0 TO L2 !下の桁から
LET d=a(i)-b(i)-brrw !同じ桁で
IF d>=0 THEN
LET c(i)=d
LET brrw=0
ELSE
LET c(i)=d+RADIX
LET brrw=1 !上の桁から借りる
END IF
NEXT i
IF brrw>0 THEN
PRINT "減算A-Bで、A>Bではありません。"
STOP
END IF
END SUB
PUBLIC SUB lmul
EXTERNAL SUB lmul(a(),b, c()) !多桁×正の整数(0~255)※10000進数なら32767
LET cy=0
FOR i=0 TO L2 !下の桁から
LET d=a(i)*b+cy
LET cy=INT(d/RADIX) !桁上がり
LET c(i)=MOD(d,RADIX) !この桁
NEXT i
IF cy>0 THEN
PRINT "乗算オーバーフロー"
STOP
END IF
END SUB
PUBLIC SUB ldiv
EXTERNAL SUB ldiv(a(),b, c()) !多桁÷正の整数(0~255)※10000進数なら32767
IF b=0 THEN
PRINT "0では割れません。"
STOP
END IF
LET r=0 !余り
FOR i=L2 TO 0 STEP -1 !上の桁から
LET d=a(i)+r
LET c(i)=INT(d/b) !商はこの桁
LET r=MOD(d,b)*RADIX !余りを下の桁へ
NEXT i
END SUB
PUBLIC SUB lcopy
EXTERNAL SUB lcopy(a(), b()) !コピー B=A
FOR i=0 TO L2 !mat b=a
LET b(i)=a(i) !同じ桁で
NEXT i
END SUB
PUBLIC FUNCTION lcomp
EXTERNAL FUNCTION lcomp(a(),b()) !比較 A>Bなら1、A=Bなら0、A<Bなら-1
FOR i=L2 TO 0 STEP -1 !上の桁から
IF a(i)>b(i) THEN
LET lcomp=1
EXIT FUNCTION
ELSEIF a(i)<b(i) THEN
LET lcomp=-1
EXIT FUNCTION
END IF
NEXT i
LET lcomp=0
END FUNCTION
つづく