ゴールシークとマクロ ① 無限遠からのアプローチ(3)

前回は、ゴールシークとの開始値を大きくしすぎると、高次の関数に於いて正しい解が求まらないという問題にぶち当たった。
infoment.hatenablog.com
今回は、この点について更に検証してみる。
f:id:Infoment:20190331112843p:plain
検証方法は、以下の通り単純だ。

Sub GoalSeekTest()
    Range("G3") = 10 ^ 30
    Range("H3").GoalSeek Goal:=0, ChangingCell:=Range("G3")
    
    ↓追加。
    Range("H3").GoalSeek Goal:=0, ChangingCell:=Range("G3")
End Sub

どのような仕掛けでゴールを探しているかは分からないが、もしゴールにたどり着く前に規定の試行回数に達しているのなら、再度探させればよい。

確認してみたところ、3回の追加で正しい解に辿り着いた。そうか、40kgの玄米を精米機に投入して、100円しか入れていなかったということか(※100円で10kg精米)。答えに辿り着く筈もない。

と、ここで気づいた。そもそも、ゴールシークの値が正しいことを、どのように確認すれば良いのか。これが、昨日に続く第2の躓き。

そこで対策として、以下を考えてみた。
案1)得られた解で繰り返し10回ほどゴールシークしてみる。
案2)得られた解と目標値の差で評価する。
案3)得られた解の、目標値に対する一致率で評価する。


案1は、得られた解の正しさに確証が持てないうえに、無駄も多い気がする。3回目で正解が出ていたなら、残り7回は無駄になる。却下。


案2は、求める値が1億の時もあれば、0.01の時もあるだろうから、「差」という絶対値で評価するのは難しい気がする。却下。


案3は、一致率何%が妥当なのか。自分で決めるしかない。しかし、その正しさを担保するものが無い。却下。


結局今回は、「直前の一致率との差が1未満になるまで」とすることにした。更に保険を掛け、11回目は行わないことにする。

Sub GoalSeekTest()

    ' 目標値。
    Dim TargetValue As Double
        TargetValue = 0
    
    ' 初期値。
    Dim InitialValue As Double
        InitialValue = 10 ^ 30
        Range("B3") = InitialValue
    
    ' 一致率。
    Dim MatchRatio(1 To 10) As Variant
    Dim i As Long
        For i = 1 To 10
            Range("H3").GoalSeek Goal:=TargetValue, ChangingCell:=Range("G3")
            MatchRatio(i) = Abs((TargetValue - Range("G3")) / TargetValue * 100)
            
            ' 一致率が1未満になったら、ループを抜ける。
            If i >= 2 Then
                If Abs(MatchRatio(i) - MatchRatio(i - 1)) < 1 Then
                    Exit For
                End If
            End If
        Next
End Sub

早速試してみる。すると、いきなり怒られた。
f:id:Infoment:20190331120859p:plain
そうか、目標値が0なら、0で割れるはずもなし。これが、3つ目の躓き。

とりあえず今回は、目標値を1にして試してみたところ、上手くいった。
f:id:Infoment:20190331121234p:plain

次回は、目標値0への対応などを検討してみよう。

参考まで。