VBAで中学数学の問題を扱おう! その4 (多項式)×(多項式)の計算
今回は多項式同士の計算です。
今回はケースに合わせて少しずつコードを修正していくのではなく
必要だと思う機能を書き出してから
それらをひとつづつコードにしていきます。
新スタイル。
はたしてできるだろうか・・・
あ。
今回からコード全部を載せるのはやめにします。
その1から読んでいる人はそろそろ自分で考えたいかなというのと。
全部載せると分量がめちゃ多くなってしまうので。。
ぜひコメントに答えを書いてみてください~
- 必要な機能
(a+b)(a+2b+5c)^2
について考えて見ましょう。
これを計算するためには何が必要か。
それぞれの多項式を認識する
それらを掛け合わせる
同類項をまとめる
まぁこの3つですよね。
それぞれについてひとことずつ。
それぞれの多項式を認識するには括弧と累乗記号が肝かなと。
それらを掛け合わせるのは掛け合わせる単項式を指定して
前に作った単項式の計算の関数を用いればいいかなと。
同類項をまとめるコードはすでに前回作ったのでそれを流用。
こんな感じです。
- 概要デザイン
Private Sub CB1_Click()
Dim siki As String
Dim answer As String
'-------------------------
'式の認識
'-------------------------
siki = TB1
'-------------------------
'多項式に分解
'-------------------------
Dim takou() As String
Call 多項式に分解(takou, siki)
'-------------------------
'展開
'-------------------------
answer = expantion(takou)
'-------------------------
'同類項をまとめる
'-------------------------
answer = Similar_Terms_Culculation(answer)
'-------------------------
'表記
'-------------------------
TB2 = answer
End Sub
このように概要を書くことはとてもいいような気がします。
関数間の連携をとりやすくなるというか。
それぞれはうまく機能しているけどうまくつながらないコードを修正するときって
自分の無能さをのろいながら行うので精神的によくないですし。
そういうつまらないことは起きない方がいいですよねー。
- それぞれの多項式を認識する
認識系のコードはもう何回も書いているので余裕ですねw
Sub 多項式に分解(trgt, kou)
Dim char As String '処理用の箱
Dim tmp As Integer '処理用の箱
Dim stock As String '処理用の箱
Dim n As Integer 'あて先の指定
Dim minus As Integer '-の処理用の箱
Dim flag(1) As Boolean
Dim h As String '累乗の処理
n = 0
For j = 1 To Len(trgt)
char = Mid(trgt, j, 1)
tmp = Asc(char) - 96
Select Case tmp
Case -56 '(の場合
If stock <> "" Then
ReDim Preserve kou(n)
kou(n) = stock
n = n + 1
stock = ""
End If
If flag(1) = True Then
stock = kou(n - 1)
For k = 2 To Val(h)
ReDim Preserve kou(n)
kou(n) = stock
n = n + 1
Next
stock = ""
h = ""
flag(1) = False
End If
flag(0) = True
Case -55 ')の場合
flag(0) = False
ReDim Preserve kou(n)
kou(n) = stock
stock = ""
n = n + 1
Case -51, -53 '-,+の場合
stock = stock & char
Case -2 '^の場合
If flag(0) = True Then
stock = stock & char
Else
flag(1) = True
End If
Case -48 To -39 '0~9の場合
If flag(1) = True And n > 0 Then
h = h & char
Else
stock = stock & char
End If
Case 1 To 26 'アルファベットの場合
stock = stock & char
Case Else
MsgBox "考慮されていない文字が入っています"
Stop
End Select
Next
If flag(1) = True Then
stock = kou(n - 1)
For k = 2 To Val(h)
ReDim Preserve kou(n)
kou(n) = stock
n = n + 1
Next
stock = ""
End If
End Sub
うーん。
まだうまいことかけない。。
select caseで一文字ずつ対応を変えて
さらにflagで前後関係に対応する
のが今のやり方ですが。
なんだか妙に複雑なコード。。。
もう少しシンプルにできないものか。。。
- それらを掛け合わせる
一つ目のコードによってtakouの配列に多項式が含まれています。
それらを掛け合わせるのが次のコード。
takouの配列の数によらないコードを書くためにいろいろ考えたのですが。
takouから式をひとつ取り出して
それらを掛け合わせる
そしてまた次の式を取り出して
という方式にしようかなと思います。
takouの式をいっぺんに処理するには
forの数をtakouの数に合わせないといけなくて
そういったコードの書き方がよくわからないので
今回はひとつずつ式で行こうと思います。
展開コードの概要。
Sub 展開(takou, keeper)
Dim adder() As String
Dim trgt As String
Dim tmp As String
trgt = kou(0)
Call 単項式に分解(trgt, keeper)
For i = 1 To UBound(kou)
trgt = kou(i)
Call 単項式に分解(trgt, adder)
Call 掛け合わせ(keeper, adder)
Next
End Sub
「単項式に分解」で多項式を単項式に分解
「掛け合わせ」で展開後の各項を個別にkeeperに格納しています
関数とsubプロシージャはクイズに。
- 同類項をまとめる
これは前回に書いたから流用~
と。
思ったら。
信じられないくらい互換性が悪い。。。
いや。
流用することはできなくはなかったのですが
おんなじ意味を持つ処理を繰り返し行うことになってしまい
気持ち悪すぎるので書き直しました。
前回書いた「同類項をまとめる」はマジで無駄だったなぁ。。。
多項式を単項式に分解して同時に係数と文字の間にカンマを入れる
同類項をまとめると同時に特定の係数に対応する
多項式に復元する
この「同時」というところが肝。
ひとつの関数やプロシージャに「同時」が増えるほどに汎用性は薄れます。
それぞれの関数に入力するための形式は限られてしまいます。
今回どのようなことが起きたかというと。
展開をしてそれぞれの項を単項式として配列に格納
同類項にまとめるために形式を整える(せっかく分けた単項式を多項式に復元する)
それを単項式に分解しながら特別な処理をする
同類項をまとめながら係数の処理をする
またそれを多項式に復元する
というおばかなやり方。
これを結構がんばって修正しました。
単項式に分解する
特別な処理をする
同類項につつ係数の処理をする
多項式に復元する
3つ目の処理は分解するとむしろ面倒になりそうなので。
あとでまた後悔するのだろうか。。。
だとしたら「同類項をまとめる」コードを書いた当時はこれを"よかれ"と思って書いたわけで
それがあだになるとわかるということは
成長の証なのかも?
まず概要
Dim co() As String
Call 加工処理(keeper, co)
Call 同類項をまとめる(keeper, co)
answer = line_restoration3(keeper)
それぞれの関数やsubプロシージャはクイズで。
- まとめ
試行錯誤したあとの概要はこんな感じ。
Private Sub CB1_Click()
Dim siki As String
Dim answer As String
'-------------------------
'式の認識
'-------------------------
siki = TB1
'-------------------------
'多項式に分解
'-------------------------
Dim takou() As String
Call 多項式に分解(siki, takou)
'-------------------------
'展開
'-------------------------
Dim keeper() As String
Call 展開(takou, keeper)
'-------------------------
'同類項をまとめる
'-------------------------
Dim co() As String
Call 加工処理(keeper, co)
Call 同類項をまとめる(keeper, co)
answer = line_restoration3(keeper)
'-------------------------
'表記
'-------------------------
TB2 = answer
End Sub
んー。
書きながら成長しているから仕方がないのですが。
それぞれの処理の深さが一致していないですね。。。
原因は最初の概要の考え方がぬるいこと。
はて。
あっているのかわからん。。。
ちょっと式を簡単にしましょう。
うん。
あってますね。
そろそろユーザーフォームに出力するのも限界ですねー。
- 思ったこと
ひとつの関数で複数の事を行おうとするとろくなことにならない。
流用できないので結局細かく再分解することになる。
これに実感したことが一番の収穫です。
知ってはいたはずなのですがなぜか実践できていませんでした。
- 次回の予定
ユーザーフォームへの出力に限界を感じているので
次回はシートに見やすく出力するコードを書きましょう。