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

更新日:2003/2/5

多倍長計算

5.1 多倍長計算の準備

(1)加算

多倍長計算が宿題になっている。多倍長計算とは、VB.NETで扱える数よりも桁数の大きい数の計算である。
例えば、100桁の数同士のかけ算などである。
 まず、加算を考える。大きな数を1つの文字列として考え、1桁ずつa(i)という配列に入れる。i=1~naとしておく。
各a(i)は、0~9までの数である。同様にb(j)を考える。ここで、j=1~nbである。
 なお、a(1)が1の桁である整数を考えている。
aとbとを足した結果をcという配列に入れる。a、b等は、数値型で計算の対象である。

(2)一桁ずつ足していくと

下から1桁ずつ加算することを考えると
 work=a(1)+b(1)として、work>=10であれば、agari=1としてwork=work-10、未満ならば、agari=0
 c(1)=work
 s=2~max+1として(maxは、na及びnbのうち、大きい方)
  work=a(s)+b(s)+agari、work>=10ならば、agari=1として、work=work-10、未満ならば、agari=0
  c(s)=work
 ただし、各a、bには、max+1まで、空の配列にはゼロが入っていて計算には支障がないものとする。
すなわち、K=1の場合で、99+999については、0099+0999として考える。
 余分な前ゼロは、計算結果を文字列に戻す際に取り去る。

(3)K桁ずつ足していきたいと考えると

大きな数を1桁ずつ配列に当てはめるのではなくて、K桁ずつa(i)等に当てはめることを考えよう。
 もし、すでに各a等に当てはめてあるとすると、上記で、繰り上がりの判定を10ではなくて、10^Kで行うことになる。例えば、K=4とすると、10000で判定することになる。
それ以外は、そのまま、成り立つことになる。

5.2 加算ルーチン

(1)大きな数字を文字列とし見なして数値型配列に入れる

大きな数字をstr1という文字列と見なす。例えば、str1="123456789"のような。
これをK桁ずつに1の桁から順に区切って配列aに入れる方法を考える。
もし、K=2であれば、a(1)=Val("89")、a(2)=Val("67")・・
この際、str1の長さがKの整数倍でなければ、整数倍になるようにstr1の前にスペースを追加しておく。
結果、str1=" 123456789"となる。j=Len(str1)/Kとすると
 i=j~1について
  a(j-i+1)=Val(Mid(str1,K*(i-1)+1,K))

(2)配列から文字列を復元

計算の結果、数値配列cに答えが求まったとする。配列の添え字の最大値は、maxとしておく。
以上の考え方が正しいかどうかをエクセルで検算してみた。
c(i)に結果が求まっているとして、文字列に復元する方法は、答えを入れる文字列をstr3として、
Excel2000のVBAでは、次のようになる。
 str3 = "": j = 0
 For i = nmax + 1 To 1 Step -1
   If j = 0 And c(i) = 0 Then GoTo Loop1
   If j = 1 Then
     strw = Trim(str(c(i)))
     strw = String(k - Len(strw), "0") + strw
     str3 = str3 + strw
    Else
     strw = Trim(str(c(i)))
     str3 = strw
     j = 1
   End If
Loop1:
 Next i
 If str3 = "" Then str3 = "0"
最後のif文は、結果がゼロであった場合にすべてブランクになってしまうので、それを修正するためのものである。

5.3 エクセルで確認してみよう

 前述のようにエクセルで確認してみた。
 確認に使用したエクセルブックを例によって「自作もの」コーナーに置いたので、ご興味のある方は、ダウンロードして試してみてほしい。「TabaichoKasanExcel.lzh」です。
 なお、Kの値は、1~4までは、問題なく動作するが6では、オーバーフローになる。
これは、a等の配列変数等がIntegerで宣言されているからである。
 ただし、第2回に記載したようにIntegerは、VB.NETでは、VBAのLongと見なされるので同じコードをVB.NETで書けば、K=6でも動作すると考えられる。

5.4 VB.NETで書いてみる

(1)フォーム

自作ものコーナーに「TabichoKasan.lzh」として、追加してあります。実行形式のみです。
フォームには、整数値を入れるテキストボックスを2つと桁数を入れるテキストボックス及び加算した文字列を
入れるテキストボックスを作成した。
コードは、次のとおり。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 Dim str1, str2, str3 As String
 Dim k As Integer
 str1 = TextBox1.Text
 str2 = TextBox2.Text
 k = Val(TextBox4.Text)
 If k > 6 Then
 TextBox3.Text = "k が大きすぎます"
 Else
 str3 = FPL(str1, str2, k)
 TextBox3.Text = str3
End If
End Sub

(2)関数FPL

 エクセルブックのVBAとほとんど同一なので、ちょっと、手抜きして説明抜きでコードを貼り付ける。
加算関数FPLは、文字変数str1とstr2と桁数kを渡すと加算結果を文字として返す関数である。

Module Module1
Private k As Short

Function FPL(ByRef strw1 As String, ByRef strw2 As String, ByRef kw As Short) As String
 Dim a(200), b(200), c(200) As Integer
 Dim i, j, na, nb, nmax, agari, work As Integer
 Dim str1, str2, str3, strw As String
 k = kw
 str1 = MaeSpace(strw1)
 str2 = MaeSpace(strw2)
 ' 配列に割り振り
 j = Len(str1) / k : na = j
 For i = j To 1 Step -1
  a(j - i + 1) = Val(Mid(str1, k * (i - 1) + 1, k))
 Next i
 j = Len(str2) / k : nb = j
 For i = j To 1 Step -1
  b(j - i + 1) = Val(Mid(str2, k * (i - 1) + 1, k))
 Next i

 If na > nb Then nmax = na Else nmax = nb
 For i = 1 To nmax + 1
  If i > na Then a(i) = 0
  If i > nb Then b(i) = 0
  c(i) = 0
 Next i

 '加算
 agari = 0
 For i = 1 To nmax + 1
  work = a(i) + b(i) + agari
  If work >= 10 ^ k Then
   agari = 1
   work = work - 10 ^ k
  Else
   agari = 0
  End If
  c(i) = work
 Next i
 '配列に書き戻し
 str3 = "" : j = 0
 For i = nmax + 1 To 1 Step -1
  If j = 0 And c(i) = 0 Then GoTo Loop1
  If j = 1 Then
   strw = Trim(Str(c(i)))
   strw = StrDup(k - Len(strw), "0") + strw
   str3 = str3 + strw
  Else
   strw = Trim(Str(c(i)))
   str3 = strw
   j = 1
  End If
Loop1:
 Next i
 If str3 = "" Then str3 = "0"
 FPL = str3
End Function

Private Function MaeSpace(ByRef strw As String) As String
 Dim i, j As Integer
 i = Len(strw)
 MaeSpace = strw
 j = i Mod k
 If j > 0 Then
  MaeSpace = Space(k - j) + strw
 End If
End Function

End Module

5.5 新しい関数

新しい関数が出てきた。一つは、Space(数値)である。これは、数値個の空白を与える。
2つめは、StrDup(数値,文字)で数値個の文字を与える。(文字列の場合は、先頭1文字)

5.6 加算ルーチンのテスト

加算ルーチンのテストのためフィボナッチ数を求めるプログラムを作成してみた。

フィボナッチ数とは、F(n)=F(n-1)+F(n-2)で定義される数である。上記では、F(0)=0、F(1)=1で計算させている。「自作もの」コーナーにアップした。

VB.NETはじめるに戻る