更新日:2003/2/5
多倍長計算が宿題になっている。多倍長計算とは、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等は、数値型で計算の対象である。
下から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として考える。
余分な前ゼロは、計算結果を文字列に戻す際に取り去る。
大きな数を1桁ずつ配列に当てはめるのではなくて、K桁ずつa(i)等に当てはめることを考えよう。
もし、すでに各a等に当てはめてあるとすると、上記で、繰り上がりの判定を10ではなくて、10^Kで行うことになる。例えば、K=4とすると、10000で判定することになる。
それ以外は、そのまま、成り立つことになる。
大きな数字を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))
計算の結果、数値配列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文は、結果がゼロであった場合にすべてブランクになってしまうので、それを修正するためのものである。
前述のようにエクセルで確認してみた。
確認に使用したエクセルブックを例によって「自作もの」コーナーに置いたので、ご興味のある方は、ダウンロードして試してみてほしい。「TabaichoKasanExcel.lzh」です。
なお、Kの値は、1~4までは、問題なく動作するが6では、オーバーフローになる。
これは、a等の配列変数等がIntegerで宣言されているからである。
ただし、第2回に記載したようにIntegerは、VB.NETでは、VBAのLongと見なされるので同じコードをVB.NETで書けば、K=6でも動作すると考えられる。
自作ものコーナーに「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
エクセルブックの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
新しい関数が出てきた。一つは、Space(数値)である。これは、数値個の空白を与える。
2つめは、StrDup(数値,文字)で数値個の文字を与える。(文字列の場合は、先頭1文字)
加算ルーチンのテストのためフィボナッチ数を求めるプログラムを作成してみた。
フィボナッチ数とは、F(n)=F(n-1)+F(n-2)で定義される数である。上記では、F(0)=0、F(1)=1で計算させている。「自作もの」コーナーにアップした。