VB.NETはじめる(その8)

更新日:2003/9/1

多倍長計算 加減乗除編 その1

8.1 加算から加減乗除へ

(1)はじめに

大きな数の剰余を求めたいという理由から始まった多倍長計算であるが、だいぶ、間が開いてしまった。
ところが、2003/8のはじめに「Ryo Kanbayashi」様よりメールがあり、加算以外に減算、乗算についても関数を開発されたということで、データをお送りいただいた。
このことに刺激されて、早急に加減乗除のそれぞれの関数を製作していきたい。
以下では、まず、新しいフォームを紹介する。

(2)新しいフォーム

多倍長の加減乗除をテストするための新しいフォームを下記に掲げる。



以前のフォームでは、フィボナッチ数列を利用した加算性能テストのため、繰り返し計算を行っていたが
今回は、その必要がないため、繰り返し数のテキストボックスを省いた。
その代わりに除算の際の商と剰余を入れるため、dというテキストボックスを新規に用意した。
ただし、桁数の項は、とりあえず、cの桁数を表示することとしている。
また、保存のメニューを実行する際にdの保存と読込を追加した。

8.2 減算

(1)減算のロジック

以下では、私の書いた減算の骨子部分を紹介してみよう。
'減算
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乗である。この個所の前後は、加算とほとんど一緒である。

(2)符号の扱い

ここで、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を交換してしまうという戦略である。その場合は、マイナス符号を結果に付ける。
なお、私が拝見した範囲では、氏の場合も減算の骨子は、同等である。

8.3 符号を含んだ場合に拡張

(1)場合に分ける

Kanbayashi氏の関数を参考にしつつ、私なりに加減算の場合をそれぞれのケースに分けて考えた。
以下の表内のa、bは、マイナス符号を取り去った絶対値で考えている。
また、FPL()、FMN()は、それぞれ従来の(私の)加算、減算関数である。

加算(新) 減算(新)
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)

(2)新加算関数

上記の表を基に新加算関数、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氏にならって、文字列長が同一の際のみ文字列同士を比較して大小を決め、文字列長が異なる場合は、長い方を大としている。

(3)新減算関数

同様に新減算関数、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()は、従来の加算及び減算関数である。

8.4 自作ものに追加

(1)加減算のみ可能なもの

自作ものコーナーにアップしました。実行ファイルとフォーム、モジュール等である。
フォームは、加減乗除に対応しているが、実際は、加減算のみ実行可能である。
名称は、Tabaichokagenzyozyo.lzhである。

(2)減算のExcelブック

減算方法の確認用のExcelブックを自作ものに追加した。使用方法は、加算の場合と同様である。
なお、k=4までである。名称は、TabaichoGenzanExcel.LZHである。

(3)乗算

近々、Kanbayashi氏の関数を参考にして、乗算も可能にしていきたい。
最後にこの場をお借りして、Ryo Kanbayashi氏のご教示に対しまして、お礼を申し上げます。

VB.NETはじめるに戻る