更新日:2003/9/1
大きな数の剰余を求めたいという理由から始まった多倍長計算であるが、だいぶ、間が開いてしまった。
ところが、2003/8のはじめに「Ryo Kanbayashi」様よりメールがあり、加算以外に減算、乗算についても関数を開発されたということで、データをお送りいただいた。
このことに刺激されて、早急に加減乗除のそれぞれの関数を製作していきたい。
以下では、まず、新しいフォームを紹介する。
多倍長の加減乗除をテストするための新しいフォームを下記に掲げる。
以前のフォームでは、フィボナッチ数列を利用した加算性能テストのため、繰り返し計算を行っていたが
今回は、その必要がないため、繰り返し数のテキストボックスを省いた。
その代わりに除算の際の商と剰余を入れるため、dというテキストボックスを新規に用意した。
ただし、桁数の項は、とりあえず、cの桁数を表示することとしている。
また、保存のメニューを実行する際にdの保存と読込を追加した。
以下では、私の書いた減算の骨子部分を紹介してみよう。
'減算
kari = 0
For i = 1 To nmax
work = a(i) - b(i) - kari
If work < 0 Then
kari = 1
work = work + kk
Else
kari = 0
End If
c(i) = work
Next i
ここで、復習しておくとa(i)は、引かれる数の配列、b(i)が引く数の配列である。
kkというのは、10のk乗である。この個所の前後は、加算とほとんど一緒である。
ここで、Kanbayashi氏の関数を拝見した。氏は、符号を考慮して加減算を一緒に扱う関数を作られている。
私の関数では、a>=bという前提で減算を行っているが、一般には、氏のように符号を含んだ数を扱えないと実用的ではない。
そのためには、大きな数の大小比較が問題になる。もし、両者正であって、b>aならば、b-aを計算して結果の数字にマイナスを付ければよい。氏は、そのように計算をされている。
少し長いが、その部分を引用させてもらおう。
なお、それぞれにマイナス符号を含む数を扱えるようにしてあるので、少し、複雑である。
Function DoublePlusMinus(ByRef strOne As String, ByRef strTwo As String, ByRef COneUse As Integer) As String
Dim a(200), b(200), c(200) As Double
Dim i, j, na, nb, nmax, up, work As Double
Dim x, y As Integer
Dim str1, str2, str3, tstr As String
Dim blnMinusFlag1 As Boolean '与えられた数がマイナスであるかどうか
Dim blnMinusFlag2 As Boolean '与えられた数がマイナスであるかどうか
Dim strTempolaly As String '一時保存用変数
Dim blnTempolalyFlag As Boolean
If Left(strOne, 1) = "-" Then
blnMinusFlag1 = True
strOne = Right(strOne, Len(strOne) - 1)
End If
If Left(strTwo, 1) = "-" Then
blnMinusFlag2 = True
strTwo = Right(strTwo, Len(strTwo) - 1)
End If
If Len(strTwo) > Len(strOne) Then '以下、絶対値において、strone>strtwoにする
strTempolaly = strOne 'strtwoの方がけた数が大きい場合
blnTempolalyFlag = blnMinusFlag1
strOne = strTwo
blnMinusFlag1 = blnMinusFlag2
strTwo = strTempolaly
blnMinusFlag2 = blnTempolalyFlag
ElseIf Len(strOne) = Len(strTwo) Then 'けた数が同じ場合
For x = 1 To Len(strOne) '左から一けたずつ大小比較をして行く
If Val(Mid(strOne, x, 1)) < Val(Mid(strTwo, x, 1)) Then
strTempolaly = strOne 'strtwoの方が絶対値が大きい場合
blnTempolalyFlag = blnMinusFlag1
strOne = strTwo
blnMinusFlag1 = blnMinusFlag2
strTwo = strTempolaly
blnMinusFlag2 = blnTempolalyFlag
Exit For
End If
Next x
End If '絶対値によって比較完了
というように、a、bを配列に格納する前に大小比較を行い、b>aの場合は、配列に収納する
前にa、bを交換してしまうという戦略である。その場合は、マイナス符号を結果に付ける。
なお、私が拝見した範囲では、氏の場合も減算の骨子は、同等である。
Kanbayashi氏の関数を参考にしつつ、私なりに加減算の場合をそれぞれのケースに分けて考えた。
以下の表内のa、bは、マイナス符号を取り去った絶対値で考えている。
また、FPL()、FMN()は、それぞれ従来の(私の)加算、減算関数である。
a | b | 加算(新) | 減算(新) |
+ | + | c=FPL(a,b) | a>=bならば、c=FMN(a,b) a<bならば、c=-FMN(b,a) |
+ | - | a>=bならば、c=FMN(a,b) a<bならば、c=-FMN(b,a) |
c=FPL(a,b) |
- | + | a>=bならば、c=-FMN(a,b) a<bならば、c=FMN(b,a) |
c=-FPL(a,b) |
- | - | c=-FPL(a,b) | a>=bならば、c=-FMN(a,b) a<bならば、c=FMN(b,a) |
上記の表を基に新加算関数、newFPL()を以下のように構成した。
Function newFPL(ByRef strw1 As String, ByRef strw2 As String, ByRef kw As Integer) As String
'多倍長加算ルーチン : TA : 2003/8/31
Dim hugo1, hugo2 As String
hugo1 = "+" : hugo2 = "+"
If Left(strw1, 1) = "-" Then
hugo1 = "-"
strw1 = Right(strw1, Len(strw1) - 1)
End If
If Left(strw2, 1) = "-" Then
hugo2 = "-"
strw2 = Right(strw2, Len(strw2) - 1)
End If
Select Case hugo1 & hugo2
Case "++"
newFPL = FPL(strw1, strw2, kw)
Case "+-"
If hikaku(strw1, strw2) = True Then
newFPL = FMN(strw1, strw2, kw)
Else
newFPL = "-" & FMN(strw2, strw1, kw)
End If
Case "-+"
If hikaku(strw1, strw2) = True Then
newFPL = "-" & FMN(strw1, strw2, kw)
Else
newFPL = FMN(strw2, strw1, kw)
End If
Case "--"
newFPL = "-" & FPL(strw1, strw2, kw)
End Select
End Function
なお、FPL()、FMN()は、従来の加算及び減算関数である。
また、hikaku()は、文字列を比較する関数である。
具体的には、次のようになる。strw1>=strw2の時に真となる。
Function hikaku(ByRef strw1 As String, ByRef strw2 As String) As Boolean
If Len(strw1) > Len(strw2) Then
hikaku = True
Else
If Len(strw1) < Len(strw2) Then
hikaku = False
Else
If StrComp(strw1, strw2, CompareMethod.Binary) >= 0 Then
hikaku = True
Else
hikaku = False
End If
End If
End If
End Function
ここで、Kanbayashi氏にならって、文字列長が同一の際のみ文字列同士を比較して大小を決め、文字列長が異なる場合は、長い方を大としている。
同様に新減算関数、newFMN()を次のように構成した。
Function newFMN(ByRef strw1 As String, ByRef strw2 As String, ByRef kw As Integer) As String
'多倍長減算ルーチン : TA : 2003/8/31
Dim hugo1, hugo2 As String
hugo1 = "+" : hugo2 = "+"
If Left(strw1, 1) = "-" Then
hugo1 = "-"
strw1 = Right(strw1, Len(strw1) - 1)
End If
If Left(strw2, 1) = "-" Then
hugo2 = "-"
strw2 = Right(strw2, Len(strw2) - 1)
End If
Select Case hugo1 & hugo2
Case "++"
If hikaku(strw1, strw2) = True Then
newFMN = FMN(strw1, strw2, kw)
Else
newFMN = "-" & FMN(strw2, strw1, kw)
End If
Case "+-"
newFMN = FPL(strw1, strw2, kw)
Case "-+"
newFMN = "-" & FPL(strw1, strw2, kw)
Case "--"
If hikaku(strw1, strw2) = True Then
newFMN = "-" & FMN(strw1, strw2, kw)
Else
newFMN = FMN(strw2, strw1, kw)
End If
End Select
End Function
なお、FPL()、FMN()は、従来の加算及び減算関数である。
自作ものコーナーにアップしました。実行ファイルとフォーム、モジュール等である。
フォームは、加減乗除に対応しているが、実際は、加減算のみ実行可能である。
名称は、Tabaichokagenzyozyo.lzhである。
減算方法の確認用のExcelブックを自作ものに追加した。使用方法は、加算の場合と同様である。
なお、k=4までである。名称は、TabaichoGenzanExcel.LZHである。
近々、Kanbayashi氏の関数を参考にして、乗算も可能にしていきたい。
最後にこの場をお借りして、Ryo Kanbayashi氏のご教示に対しまして、お礼を申し上げます。