vbaで数値計算 03 数式実装パターン
TRANSCRIPT
2017-01更新 熊本高専森下功啓
VBAで数値計算03
本資料の目次
プログラミングのTipsVBAのTips問題と実装パターン数式実装のコツ数値微分を実装する練習問題その他
2
プログラミングのTIPS 小さなデザインパターン
3
読みやすいコードは良い
読みやすく、短く、意味の分かりやすいコードは良いコード
4
IOCCC1998年大会で優勝した、フライトシミュレータのクソプログラム
C言語製(実際にビルドできて動く)
速く動けばなお良い
利用メモリ量と計算量が少ない(=速い)コードは良いコード
結局はケースバイケースだが、基本的に読みやすいコードを書くことを心がけて欲しい。
5
字下げしよう
字下げにより、スコープを明示すると頭の整理がつきやすい
6BAD GOOD@VBA
無理に一行にまとめない
短くするために、一行にまとめると読み難くなる場合があります。特に、If文でelseやelse ifを伴う場合です。非常に単純な場合や何個も同じパターンでIf文が並ぶのではない限りは一行にまとめることは止めましょう。
7
Better@VBA
GOTOをなるだけ使わない
多重ループからの脱出を助けるためにVBAではgoto文が用意されていますが、goto文は乱用された過去によって評判がよくありません。Pythonの様にgoto文が存在しない言語もあります。gotoで飛んだ先が明確な場合以外でのgotoの使用は避けましょう。
8
@Python関数のreturnで処理を抜けている例
VBA TIPS9
VBAのFOR文仕様 1/3
VBAのfor文はToの後ろに指定された値を含む値までTrueと判断されます。Cで書くと、以下のような感じです。iはループ内が1回処理されたら増えます。<=が味噌です。for(int i = 0; i <= 100; i++){} // 101回ループでは、次のループは何回実行されるでしょうか?
10
Count = 1For i = 0 To 1 Step 0.01
Cells(Count, 1) = iCount = Count + 1
Next I
数学的には0.01を100回足せば1.0になるはずなので、101回ループしそうです。
@VBA
VBAのFOR文仕様 2/3
試しに、VBAで3パターンのループを作ってみました。
11
結果
プログラム 整数版は101回ループ
1.01までにすると101回ループ
ステップ0.01で1までにすると100回ループ
100回しか実行されていな
い・・・
VBAのFOR文仕様 3/3
実は、0.01を99回足すと0.99よりも僅かに大きくなります。これはdouble型では実数を2進数で正確に表すことができないことが原因です。10進数型の変数を使うと数学的に正しく処理しますが、double型の計算には微小な誤差が有ります。「For i = 0 To 1 Step 0.01」では、101回目はiが1.000000000000000よりも大きくなり、評価がFalseとなってループ内が実行されません。
12
問題と実装パターン 小さなデザインパターン
13
14
一次元配列例:Excelの列や行への処理
ForやWhileによる一重ループ
ループ回数は実際のデータ数に合わせるか、うまくループの脱出条件を仕掛ける。
処理対象 実装
For i = 0 To 100‘ 何か処理
Next i @VBA
15
二次元配列,行列例:Excelの表の処理,
行列演算
ForやWhileによる二重ループ
ループ回数は実際のデータ数に合わせるか、うまくループの脱出条件を仕掛ける。
処理対象
For i = 0 To 100For j = 0 To 100
‘ 何か処理Next j
Next i
実装
@VBA
16
n次元配列(絵は3次元)
ForやWhileによるn重ループ
(Nextは省略しているが、実際には必要)
処理対象 実装
http://www.cse.kyoto-su.ac.jp/~oomoto/lecture/program/C/array-images/3D_array.png
For i = 0 To 100For j = 0 To 100
For k = 0 To 100・・・ @VBA
17
�
�
𝑛𝑛!
�
足し続けたり、かけ続けたり、積分したり
ForやWhileによる一重ループ
足し続けるパターン
掛け続けるパターン
処理対象 実装
tasu = 0For i = 0 To 100tasu = tasu + Nanika
Next i
kakeru = 1For i = 0 To 100kakeru = kakeru * Nanika
Next i
Nanikaを好きな数字や関数や変数に置き換えれば良い。
@VBA
18
時間経過を伴う計算少しずつ増やす計算
ForやWhileによる一重ループ
ループの中で、時間を進める例
処理対象
実装time_ = 0time_step = 0.01For i = 0 To 100‘ time_を使った何か処理time_ = time_ + time_step
Next i
𝑦𝑦 = 𝑓𝑓(𝑡𝑡)𝑡𝑡を0.01ずつ変化させながら計算させたい
For time_ = 0# To 100 Step 0.01‘ time_を使った何か処理
Next i
パターン1
パターン2
@VBA
time_ = 0time_step = 0.01Do
' time_を使った何か処理time_ = time_ + time_step
Loop While time_ < 100
パターン3
注意
ここまでに紹介したパターンは、言語に余り依存しない構造ですが、数値計算に特化した言語などではもっと良い書き方が有ります。VBAではこう書くんだと思いつつ、他の言語に取り組むことになったら少し調べてみることをお勧めします。
19
数式実装のコツ実装はコーディングとも言い、プログラムのソースコードを書くことを指す。
20
複雑な問題は、簡単な問題の組み合わせに分解する例:exのマクローリン展開
21
http://mathtrain.jp/maclaurin
ループで足し算
理論微分がどうなるか計算
構成する要素の関数を個別にプログラムでどう記述するか考える
全体的な構成を把握したら、ざっくりとしたプログラムを組む。その後、カウンタ変数などを考える。このとき、1周目,2周目・・・と具体的に変数の値を紙に値を書いていくと良いかもしれない。
階乗は関数で定義した方がスッキリしそう
数値微分を実装する22
微分の定義
微分とは、変化率を求めることである。ある点における微分値とは、その点における接線の傾きに等しい。微分値は微分係数ともいう。接線は法線に直交する。微分の定義式を示す→
23法線
接線
x
y
C
D
x Δx
Δy
f(x)
f(x)
C-D𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑 = lim
∆𝑥𝑥→+0
∆𝑦𝑦∆𝑑𝑑 = lim
∆𝑥𝑥→+0
𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑
数値微分の計算戦略
∆𝑑𝑑を小さく取り、下記の式で微分を近似する。
24
𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑~
𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑
∆𝑑𝑑 ≪ 1
数値微分の実装
微分の近似式をそのままコードに直してみる。ここで、func()は任意の関数であるものとする。
25
dx = 0.01dydx = (func(x + dx) – func(x)) / dx
𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑~
𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑
∆𝑑𝑑 ≪ 1
26
ここまでは1階微分でした。更に、2階微分について見ていきましょう。
2階微分
変曲点を探すには2階微分が必要になります。2階微分とは、変化率の変化率です。
数式で書くと、𝑑𝑑2𝑦𝑦𝑑𝑑𝑥𝑥2
さっぱりしすぎていますね。
27
C
D
Δx
Δy
f’(x)
C-D
𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑 = lim
∆𝑥𝑥→+0
∆𝑦𝑦∆𝑑𝑑 = lim
∆𝑥𝑥→+0
𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑 = 𝑓𝑓′
𝑓𝑓′′ = lim∆𝑥𝑥→+0
𝑓𝑓′ 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓′(𝑑𝑑)∆𝑑𝑑
http://mathtrain.jp/wp-content/uploads/2015/08/henkyokuten-254x300.png
式の整理
計算量を減らすために、式を整理
28
𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑 = lim
∆𝑥𝑥→+0
∆𝑦𝑦∆𝑑𝑑 = lim
∆𝑥𝑥→+0
𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑 = 𝑓𝑓′
𝑓𝑓′′ = lim∆𝑥𝑥→+0
𝑓𝑓′ 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓′(𝑑𝑑)∆𝑑𝑑
= lim∆𝑥𝑥→+0
𝑓𝑓 𝑑𝑑 + 2∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑 + ∆𝑑𝑑)∆𝑑𝑑 −
𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑
1∆𝑑𝑑
= lim∆𝑥𝑥→+0
𝑓𝑓 𝑑𝑑 + 2∆𝑑𝑑 − 2𝑓𝑓(𝑑𝑑 + ∆𝑑𝑑) + 𝑓𝑓(𝑑𝑑)∆𝑑𝑑2
(1)
(2)は(1)よりも計算量が少ない。
(2)
2階微分の実装
2階微分の近似式をそのままコードに直してみる。ここで、func()は任意の関数であるものとする。
29
dx = 0.01d2ydx2 = (func(x + 2*dx) - 2*func(x + dx) + func(x)) / dx / dx
𝑑𝑑2𝑦𝑦𝑑𝑑𝑑𝑑2 ~
𝑓𝑓 𝑑𝑑 + 2∆𝑑𝑑 − 2𝑓𝑓(𝑑𝑑 + ∆𝑑𝑑) + 𝑓𝑓(𝑑𝑑)∆𝑑𝑑2 ∆𝑑𝑑 ≪ 1
練習問題30
問1 2次関数の微分
y = ax2 + bx + c(1) 係数は0以外の任意の定数とし、xについて1階微分する関数を作成せよ。(2) 係数は0以外の任意の定数とし、xについて2階微分する関数を作成せよ。(3) y=0の実数解が存在することを確認する関数を実装せよ。(4) -10 >= x >= 10の定義域において関数を計算し、グラフを作成せよ。グラフ作成部分はExcelのグラフ機能を用いて手動で作成しても良い。言語指定:なし
31
問2 標準シグモイド関数
(1) xについて1階微分する関数を作成せよ。(2) xについて2階微分する関数を作成せよ。(3) -10 >= x >= 10の定義域において関数を計算し、グラフを作成せよ。グラフ作成部分はExcelのグラフ機能を用いて手動で作成しても良い。言語指定:なし
32
問3 極大・極小
y = ax2 + bx + c係数が変数で与えられるとき、この関数の傾きが0となる座標を求める関数を作成せよ。
ヒント:微分値を使って求めても良い(勾配法)。また、数学的に解いても良い。さらに、xを走査して極大・極小を見つけることで求めても良い。言語指定:なし
33
その他34
参考文献
SAK Streets - VB 開発言語資料 http://sak.cool.coocan.jp/w_sak3/doc/sysbrd/sak3vb.htm 基本的にVB6.0の解説だが、VBAにほぼそのまま適用できる。かなり詳しい。
35