コンピュータ(プログラム作成者)から与えられた問題を解くより、「僕は、私はこれが解きたい」と、問題をコンピュータに入力し、まるでコンピュータと対話するかのように、解答を促されたり、タイムリーにヒントが出てきたり、少しでも、学ぶ側が能動的、自発的に学習できることに拘って数学ソフトを作成しています。
拙作なのですが、1次方程式をコンピュータに解かせるプログラムを紹介したいと思います。
「2x+(x+3)=x-5」を念頭に置き、VisualBasicで解かせてみます。
私たちは、1次方程式を次の順序で解きます。
①括弧をはずす。
②文字を含む項は左辺に、定数項は右辺に移項する。
③同類項をまとめる。
④xの係数で両辺をわる。
また、同類項をまとめる段階で「2x+x-x=-5-3」となりますが、「2x+x」が「3x」となるためには、係数が必要です。
人は数式を簡略してきました。「1×3=3」ですものね。「1x=x」としても問題はありません。でも、これがコンピュータで計算させるときにはやっかいです。例外は理解してもらえません。ですから、「2x+(x+3)=x-5」を文字列操作で「+2x+1+1(+1x+3)=+1x-5」にします。項は必ず符号と数と文字を持つです。(定数項は別ですが)
括弧をはずすときには「+1(+1x+3)」で「+1」を「+1x」にかけ、さらに「+3」にもかけます。「+1x」や「+3」は何かというと項です。同類項をまとめるにしても、項同志の計算になりますので、式を項に分解することが必要です(項を配列に格納します)。
ここまでで、「+」や「1」を復元するルーチン(プロシージャ?)と、項を配列に格納するプロシージャを作ります。さらに、括弧の付いた1次方程式は保留し、「3x+3=x-5」を解くことから始めたいと思います。
まず、Form1にButton1とTextBox1を配置し、TextBox1をMultiLineにチェックを付け、下方に伸ばします。次に、変数ですが、式を「Formula」、項を「Term()」とし、プロシージャ外で宣言します。 Public Class Form1の下です。
Private Formula As String
Private Term(20) As String
「+」や「1」を復元するプロシージャを「Restore」、項を配列に格納するプロシージャを「TakeToTerm」と名付け、以下のように記述します。
pivate Sub Restore()
Dim i As Integer
'①式の先頭が数なら「+」をつける
If Strings.Left(Formula, 1) Like "[0-9]" Then
Formula = "+" + Formula
End If
'②「=x」なら「=+1x」とする
i = Strings.InStr(Formula, "=x")
If i > 0 Then
Formula = Strings.Mid(Formula,1, i - 1) & "=+1x" & Strings.Mid(Formula, i + 2)
End If
'③「+(」なら「+1(」とする、括弧付きのことも考えて
i = Strings.InStr(Formula, "+(")
If i > 0 Then
Formula = Strings.Mid(Formula, 1, i - 1) & "+1(" & Strings.Mid(Formula, i + 2)
End If
'④「(x」なら「(+1x」とする、括弧付きのことも考えて
i = Strings.InStr(Formula, "(x")
If i > 0 Then
Formula = Strings.Mid(Formula, 1, i - 1) & "(+1x" & Strings.Mid(Formula, i + 2)
End If
End Sub
'
Private Sub TakeToTerm()
Dim i, j, k As Integer
Dim Ltr As String
'
i = 1 : j = 2 : k = 1
Do Until Strings.Mid(Formula, i, 1) = Nothing
Ltr = Strings.Mid(Formula, j, 1)
If Ltr Like "[-+()=]" Or Ltr = "" Then
Term(k) = Strings.Mid(Formula, i, j - i)
k = k + 1
i = j
End If
j = j + 1
Loop
End Sub
上記のプログラムが正しく動いていることを確かめます。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Formula = "3x+3=x-5"
Call Restore()
Me.TextBox1.Text = Formula
End Sub
でしたら、TextBox1には「+3x+3=+1x-5」が表示されます。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Dim i As Integer
'
Formula = "3x+3=x-5"
Call Restore()
Call TakeToTerm()
i = 1
Do Until Term(i) = Nothing
Me.TextBox1.SelectedText = "Term(" & i & "):" & Term(i) & vbCrLf
i = i + 1
Loop
End Sub
上記のようにTakeToTermを加えると、
Term(1):+3x Term(2):+3 Term(3):= Term(4):+1x Term(5):-5
項を配列に格納できたので、次は移項です。文字(変数)を含んでいる項は左辺に、定数項は右辺です。符号が変わることに注意しなければいけません。また、移項する段階で文字を含んでいるかどうかをプログラムすると複雑になるので、関数を作ります。「VarTrim()」と名付けました。これは、文字(変数)を取り出します。
Public Function VarTrim(ByVal Term As String) As String
Dim i As Integer
Dim Ltr As String
'
i = 1
Do Until Strings.Mid(Term, i, 1) = Nothing
Ltr = Strings.Mid(Term, i, 1)
If Ltr Like "[-+/.0-9]" Then
Term = Strings.Mid(Term, i + 1)
Else
i = i + 1
End If
Loop
Return Term
End Function
ご覧の通り、何のことはありません。項に含まれるであろう文字(変数)以外の記号や数字を取り除いているだけです。後々のこと(分数や小数が入る)も考慮して、「.」や「/」も取り除くようにしています。また、文字(変数)が含まれていなければ、「Nothing」が返ります。
それでは、移項のプロシージャを書きます。その名の通り「Transpose」です。入力はFormulaで出力もFormulaにしています。このルーチンの中で前述の「Restore」と「TakeToTerm」が使われています。
Private Sub Transpose()
Dim Eq As Integer
Dim vTerm(20), cTerm(20) As String
Dim i, j As Integer
Dim Fm As String
'
Call Restore()
Call TakeToTerm()
'
'「=」の位置
i = 1
Do Until Term(i) = "="
i = i + 1
Loop
Eq = i
'移項(文字の項を左辺)
i = 1 : j = 1
Do Until Term(i) = Nothing
If VarTrim(Term(i)) <> Nothing And Term(i) <> "=" Then
If i < Eq Then
vTerm(j) = Term(i)
Else
If Strings.Mid(Term(i), 1, 1) = "+" Then
vTerm(j) = Strings.Replace(Term(i), "+", "-")
Else
vTerm(j) = Strings.Replace(Term(i), "-", "+")
End If
End If
j = j + 1
End If
i = i + 1
Loop
'
'移項(定数項を右辺)
i = Eq + 1 : j = 1 '先に右辺を格納
Do Until Term(i) = Nothing
If VarTrim(Term(i)) = Nothing Then
cTerm(j) = Term(i)
j = j + 1
End If
i = i + 1
Loop
'
j = j '明示的
i = 1 '左辺の格納
Do Until i = Eq
If VarTrim(Term(i)) = Nothing Then
If Strings.Mid(Term(i), 1, 1) = "+" Then
If Term(i) = "+0" Then
cTerm(j) = Term(i)
Else
cTerm(j) = Strings.Replace(Term(i), "+", "-")
End If
Else
cTerm(j) = Strings.Replace(Term(i), "-", "+")
End If
j = j + 1
End If
i = i + 1
Loop
'
'式作りTerm()とcTerm()をFmにためる
i = 1 : Fm = Nothing
Do Until vTerm(i) = Nothing
Fm = Fm & vTerm(i)
i = i + 1
Loop
Fm = Fm & "="
i = 1
Do Until cTerm(i) = Nothing
Fm = Fm & cTerm(i)
i = i + 1
Loop
Formula = Fm
Array.Clear(Term, 0, Term.Length)
End Sub
このプロシージャは、
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Formula = "3x+3=x-5"
Call Transpose()
Me.TextBox1.Text = Formula
End Sub
によって確かめることができます。「Formula="+3x-1x=-5-3"」になると思います。
次は同類項をまとめるルーチンです。名前は「SimilarTerm」としました。「Combine」のほうが適切かなと思いましたが、ぴんとこなくて…。ただ、ここで同類項をまとめるとき、「+3x」に「-1x」を加えるには「Val("+3x")+Val("-1x")」でもいいのですが、小数や分数のことも考えて、関数を作ります。Add()関数で、
Public Function Add(ByVal TermA As String, ByVal TermB As String) As String
Add = Trim(Str(Val(TermA) + Val(TermB))) & VarTrim(TermA)
If Strings.Mid(Add, 1, 1) <> "-" Then
Add = "+" & Add
End If
Return Add
End Function
これで、「SimilarTerm」は以下のようになります。
Private Sub SimilarTerm()
Dim i, j As Integer
Dim Fm As String
'
Call Restore()
Call TakeToTerm()
'Term(i)とTerm(j)が同類項ならTerm(i)に和を、Term(j)には「@」を入れる、あとで抜き取ります
i = 1
Do Until Term(i) = Nothing
j = i + 1
Do Until Term(j) = Nothing
If Term(i) <> "@" And Term(j) <> "@" And Term(i) <> "=" _
And Term(j) <> "=" And VarTrim(Term(i)) = VarTrim(Term(j)) Then
If Add(Term(i), Term(j)) = Nothing Then
Term(i) = "@"
Else
Term(i) = Add(Term(i), Term(j))
End If
Term(j) = "@"
End If
j = j + 1
Loop
i = i + 1
Loop
'式作り
i = 1 : Fm = Nothing
Do Until Term(i) = Nothing
If Term(i) <> "@" Then
Fm = Fm & Term(i)
End If
i = i + 1
Loop
Formula = Fm
Array.Clear(Term, 0, Term.Length)
End Sub
これを確かめるには、
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Formula = "+3x-1x=-5-3"
Call SimilarTerm()
Me.TextBox1.Text = Formula
End Sub
「Formula="+2x=-8"」となります。
最後は、「x」の係数で割ります。
以上、正しく動作するか、Button1.Clickイベントを下記のように記述し、実行してみてください。ただ、最後には「Val関数」を用いて処理していますが、これも、小数や分数のことを考えて工夫が必要です。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Dim ax As String
Dim b As String
Dim Eq As Integer
'
Formula = "3x+3=x-5"
Call Transpose()
Call SimilarTerm()
Eq = Strings.InStr(Formula, "=")
ax = Strings.Mid(Formula, 1, Eq - 1)
b = Strings.Mid(Formula, Eq + 1)
Formula = VarTrim(ax) & "=" & Val(b) / Val(ax)
Me.TextBox1.Text = Formula
End Sub
次に、括弧を含む1次方程式です。分配法則により括弧をはずすプロシージャ名を「Bracket」と名付けました。コードは
Private Sub Bracket()
Dim i, j, k As Integer
Dim CoB As String
Dim BFm As String
Dim FmL, FmM, FmR As String
'
Call Restore()
'
j = Strings.InStr(Formula, "(")
k = Strings.InStr(Formula, ")")
i = j - 1
Do Until Strings.Mid(Formula, i, 1) Like "[+-]"
i = i - 1
Loop
'
FmL = Strings.Mid(Formula, 1, i - 1)
FmR = Strings.Mid(Formula, k + 1)
CoB = Strings.Mid(Formula, i, j - i)
BFm = Strings.Mid(Formula, j + 1, k - j - 1)
Formula = BFm
Call TakeToTerm()
i = 1
Do Until Term(i) = Nothing
Term(i) = Trim(Str(Val(CoB) * Val(Term(i)))) & VarTrim(Term(i))
If Strings.Mid(Term(i), 1, 1) <> "-" Then
Term(i) = "+" & Term(i)
End If
i = i + 1
Loop
i = 1 : FmM = Nothing
Do Until Term(i) = Nothing
FmM = FmM & Term(i)
i = i + 1
Loop
Array.Clear(Term, 0, Term.Length)
Formula = FmL & FmM & FmR
End Sub
これを確かめるために
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Formula = "+2x+1(+1x+3)=+1x-5"
Call Bracket()
Me.TextBox1.Text = Formula
End Sub
Formula="+2x+1x+3=+1x-5"になります。
いよいよ、最後です。Formula="2x+(x+3)=x-5"とし、Button1.Clickイベントプロシージャに次のようにコードを書き込んでください。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Dim ax As String
Dim b As String
Dim Eq As Integer
'
Formula = "2x+(x+3)=x-5"
Call Bracket()
Call Transpose()
Call SimilarTerm()
Eq = Strings.InStr(Formula, "=")
ax = Strings.Mid(Formula, 1, Eq - 1)
b = Strings.Mid(Formula, Eq + 1)
Formula = VarTrim(ax) & "=" & Val(b) / Val(ax)
Me.TextBox1.Text = Formula
End Sub
答は「x=-4」となります。
さて、ここでは「Restore」を簡略しました。実際は文字(変数)は「x」だけではありませんし、長い式となると括弧が2つある場合もありますし、「(x」は式の中で1つとは限りません。また、「(3x」の場合もあります。それらに対応した「Restore」や「Bracket」をしっかりと作る必要があります。
以上2015/05/07