vbaで数値計算 03 数式実装パターン

35
2017-01 更新 熊本高専 森下功啓 VBA数値計算03

Upload: katsuhiro-morishita

Post on 07-Feb-2017

107 views

Category:

Education


1 download

TRANSCRIPT

Page 1: VBAで数値計算 03 数式実装パターン

2017-01更新 熊本高専森下功啓

VBAで数値計算03

Page 2: VBAで数値計算 03 数式実装パターン

本資料の目次

プログラミングのTipsVBAのTips問題と実装パターン数式実装のコツ数値微分を実装する練習問題その他

2

Page 3: VBAで数値計算 03 数式実装パターン

プログラミングのTIPS 小さなデザインパターン

3

Page 4: VBAで数値計算 03 数式実装パターン

読みやすいコードは良い

読みやすく、短く、意味の分かりやすいコードは良いコード

4

IOCCC1998年大会で優勝した、フライトシミュレータのクソプログラム

C言語製(実際にビルドできて動く)

Page 5: VBAで数値計算 03 数式実装パターン

速く動けばなお良い

利用メモリ量と計算量が少ない(=速い)コードは良いコード

結局はケースバイケースだが、基本的に読みやすいコードを書くことを心がけて欲しい。

5

Page 6: VBAで数値計算 03 数式実装パターン

字下げしよう

字下げにより、スコープを明示すると頭の整理がつきやすい

6BAD GOOD@VBA

Page 7: VBAで数値計算 03 数式実装パターン

無理に一行にまとめない

短くするために、一行にまとめると読み難くなる場合があります。特に、If文でelseやelse ifを伴う場合です。非常に単純な場合や何個も同じパターンでIf文が並ぶのではない限りは一行にまとめることは止めましょう。

7

Better@VBA

Page 8: VBAで数値計算 03 数式実装パターン

GOTOをなるだけ使わない

多重ループからの脱出を助けるためにVBAではgoto文が用意されていますが、goto文は乱用された過去によって評判がよくありません。Pythonの様にgoto文が存在しない言語もあります。gotoで飛んだ先が明確な場合以外でのgotoの使用は避けましょう。

8

@Python関数のreturnで処理を抜けている例

Page 9: VBAで数値計算 03 数式実装パターン

VBA TIPS9

Page 10: VBAで数値計算 03 数式実装パターン

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

Page 11: VBAで数値計算 03 数式実装パターン

VBAのFOR文仕様 2/3

試しに、VBAで3パターンのループを作ってみました。

11

結果

プログラム 整数版は101回ループ

1.01までにすると101回ループ

ステップ0.01で1までにすると100回ループ

100回しか実行されていな

い・・・

Page 12: VBAで数値計算 03 数式実装パターン

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

Page 13: VBAで数値計算 03 数式実装パターン

問題と実装パターン 小さなデザインパターン

13

Page 14: VBAで数値計算 03 数式実装パターン

14

一次元配列例:Excelの列や行への処理

ForやWhileによる一重ループ

ループ回数は実際のデータ数に合わせるか、うまくループの脱出条件を仕掛ける。

処理対象 実装

For i = 0 To 100‘ 何か処理

Next i @VBA

Page 15: VBAで数値計算 03 数式実装パターン

15

二次元配列,行列例:Excelの表の処理,

行列演算

ForやWhileによる二重ループ

ループ回数は実際のデータ数に合わせるか、うまくループの脱出条件を仕掛ける。

処理対象

For i = 0 To 100For j = 0 To 100

‘ 何か処理Next j

Next i

実装

@VBA

Page 16: VBAで数値計算 03 数式実装パターン

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

Page 17: VBAで数値計算 03 数式実装パターン

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

Page 18: VBAで数値計算 03 数式実装パターン

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

Page 19: VBAで数値計算 03 数式実装パターン

注意

ここまでに紹介したパターンは、言語に余り依存しない構造ですが、数値計算に特化した言語などではもっと良い書き方が有ります。VBAではこう書くんだと思いつつ、他の言語に取り組むことになったら少し調べてみることをお勧めします。

19

Page 20: VBAで数値計算 03 数式実装パターン

数式実装のコツ実装はコーディングとも言い、プログラムのソースコードを書くことを指す。

20

Page 21: VBAで数値計算 03 数式実装パターン

複雑な問題は、簡単な問題の組み合わせに分解する例:exのマクローリン展開

21

http://mathtrain.jp/maclaurin

ループで足し算

理論微分がどうなるか計算

構成する要素の関数を個別にプログラムでどう記述するか考える

全体的な構成を把握したら、ざっくりとしたプログラムを組む。その後、カウンタ変数などを考える。このとき、1周目,2周目・・・と具体的に変数の値を紙に値を書いていくと良いかもしれない。

階乗は関数で定義した方がスッキリしそう

Page 22: VBAで数値計算 03 数式実装パターン

数値微分を実装する22

Page 23: VBAで数値計算 03 数式実装パターン

微分の定義

微分とは、変化率を求めることである。ある点における微分値とは、その点における接線の傾きに等しい。微分値は微分係数ともいう。接線は法線に直交する。微分の定義式を示す→

23法線

接線

x

y

C

D

x Δx

Δy

f(x)

f(x)

C-D𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑 = lim

∆𝑥𝑥→+0

∆𝑦𝑦∆𝑑𝑑 = lim

∆𝑥𝑥→+0

𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑

Page 24: VBAで数値計算 03 数式実装パターン

数値微分の計算戦略

∆𝑑𝑑を小さく取り、下記の式で微分を近似する。

24

𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑~

𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑

∆𝑑𝑑 ≪ 1

Page 25: VBAで数値計算 03 数式実装パターン

数値微分の実装

微分の近似式をそのままコードに直してみる。ここで、func()は任意の関数であるものとする。

25

dx = 0.01dydx = (func(x + dx) – func(x)) / dx

𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑~

𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑

∆𝑑𝑑 ≪ 1

Page 26: VBAで数値計算 03 数式実装パターン

26

ここまでは1階微分でした。更に、2階微分について見ていきましょう。

Page 27: VBAで数値計算 03 数式実装パターン

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

Page 28: VBAで数値計算 03 数式実装パターン

式の整理

計算量を減らすために、式を整理

28

𝑑𝑑𝑦𝑦𝑑𝑑𝑑𝑑 = lim

∆𝑥𝑥→+0

∆𝑦𝑦∆𝑑𝑑 = lim

∆𝑥𝑥→+0

𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑 = 𝑓𝑓′

𝑓𝑓′′ = lim∆𝑥𝑥→+0

𝑓𝑓′ 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓′(𝑑𝑑)∆𝑑𝑑

= lim∆𝑥𝑥→+0

𝑓𝑓 𝑑𝑑 + 2∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑 + ∆𝑑𝑑)∆𝑑𝑑 −

𝑓𝑓 𝑑𝑑 + ∆𝑑𝑑 − 𝑓𝑓(𝑑𝑑)∆𝑑𝑑

1∆𝑑𝑑

= lim∆𝑥𝑥→+0

𝑓𝑓 𝑑𝑑 + 2∆𝑑𝑑 − 2𝑓𝑓(𝑑𝑑 + ∆𝑑𝑑) + 𝑓𝑓(𝑑𝑑)∆𝑑𝑑2

(1)

(2)は(1)よりも計算量が少ない。

(2)

Page 29: VBAで数値計算 03 数式実装パターン

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

Page 30: VBAで数値計算 03 数式実装パターン

練習問題30

Page 31: VBAで数値計算 03 数式実装パターン

問1 2次関数の微分

y = ax2 + bx + c(1) 係数は0以外の任意の定数とし、xについて1階微分する関数を作成せよ。(2) 係数は0以外の任意の定数とし、xについて2階微分する関数を作成せよ。(3) y=0の実数解が存在することを確認する関数を実装せよ。(4) -10 >= x >= 10の定義域において関数を計算し、グラフを作成せよ。グラフ作成部分はExcelのグラフ機能を用いて手動で作成しても良い。言語指定:なし

31

Page 32: VBAで数値計算 03 数式実装パターン

問2 標準シグモイド関数

(1) xについて1階微分する関数を作成せよ。(2) xについて2階微分する関数を作成せよ。(3) -10 >= x >= 10の定義域において関数を計算し、グラフを作成せよ。グラフ作成部分はExcelのグラフ機能を用いて手動で作成しても良い。言語指定:なし

32

Page 33: VBAで数値計算 03 数式実装パターン

問3 極大・極小

y = ax2 + bx + c係数が変数で与えられるとき、この関数の傾きが0となる座標を求める関数を作成せよ。

ヒント:微分値を使って求めても良い(勾配法)。また、数学的に解いても良い。さらに、xを走査して極大・極小を見つけることで求めても良い。言語指定:なし

33

Page 34: VBAで数値計算 03 数式実装パターン

その他34

Page 35: VBAで数値計算 03 数式実装パターン

参考文献

SAK Streets - VB 開発言語資料 http://sak.cool.coocan.jp/w_sak3/doc/sysbrd/sak3vb.htm 基本的にVB6.0の解説だが、VBAにほぼそのまま適用できる。かなり詳しい。

35