コンピュータ(プログラム作成者)から与えられた問題を解くより、「僕は、私はこれが解きたい」と、問題をコンピュータに入力し、まるでコンピュータと対話するかのように、解答を促されたり、タイムリーにヒントが出てきたり、少しでも、学ぶ側が能動的、自発的に学習できることに拘って数学ソフトを作成しています。
拙作なのですが、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