第16講 魔方陣作成の高速化(数万倍へ)
第6話 ランダム検索解説
コード再掲
Sub ms(g As Byte)
Dim i As Byte, j As Byte, k As Byte, a As Byte, b As
Byte, w As Byte
a = x(g)
b = y(g)
ii = Int((n * n) * Rnd)
For i = 0 To n * n -
1
iii = (ii + i) Mod n * n
mah(b, a) = iii +
1
・
・
・
End Sub
今話では、検索のはじめを何故ランダムに出来、それでかつ漏れなく網羅しているのか解説しましょう。
まず、Rndは1未満のランダムな小数を発生させるものです。
ですから、10以下の整数を発生させたければ、
Int(10*Rnd) とします。
Int(・)が入っているのは、10*Rndだと発生するのは10未満の小数で、例えば4.1287・・・ですから、
その小数部分を切り捨て整数にするためです。
小数から小数部分を切り捨て整数にすることを丸めるといいますが、丸めるときにInt(・)を利用すればよいのです。
C言語あたりなら、変数を整数型で宣言しておけば自動的に丸めてくれるのですが、
VBではそこは融通が利きません。
エラーの原因になりますので、丸めるときは必ずInt(・)を利用します。
さて、ii = Int((n * n) * Rnd)によって何が発生するでしょうか。
n=4ならn*n=16ですから、16未満の整数です。
ではiii = (ii + i) Mod n * nでは何をしているのでしょうか。
A Mod B はAをBで割った余りを算出するものです。
ですから、iii = (ii + i) Mod n * nはn=4なら(ii+i)を16で割った余りです。
例えば、n=4,ii=7として動きをトレースしてみましょう。
iは0から15まで動いていくので、動きは次のようになります。
i=0のとき、iii=(ii+i) Mon (n*n)=(7+0) Mod (4*4)=7 Mod 16=7
i=1のとき、iii=(ii+i) Mon (n*n)=(7+1) Mod (4*4)=8 Mod 16=8
i=2のとき、iii=(ii+i) Mon (n*n)=(7+2) Mod (4*4)=9 Mod 16=9
i=3のとき、iii=(ii+i) Mon (n*n)=(7+3) Mod (4*4)=10 Mod 16=10
i=4のとき、iii=(ii+i) Mon (n*n)=(7+4) Mod (4*4)=11 Mod 16=11
i=5のとき、iii=(ii+i) Mon (n*n)=(7+5) Mod (4*4)=12 Mod 16=12
i=6のとき、iii=(ii+i) Mon (n*n)=(7+6) Mod (4*4)=13 Mod 16=13
i=7のとき、iii=(ii+i) Mon (n*n)=(7+7) Mod (4*4)=14 Mod 16=14
i=8のとき、iii=(ii+i) Mon (n*n)=(7+8) Mod (4*4)=15 Mod 16=15
i=9のとき、iii=(ii+i) Mon (n*n)=(7+9) Mod (4*4)=16 Mod 16=0
i=10のとき、iii=(ii+i) Mon (n*n)=(7+10) Mod (4*4)=17 Mod 16=1
i=11のとき、iii=(ii+i) Mon (n*n)=(7+11) Mod (4*4)=18 Mod 16=2
i=12のとき、iii=(ii+i) Mon (n*n)=(7+12) Mod (4*4)=19 Mod 16=3
i=13のとき、iii=(ii+i) Mon (n*n)=(7+13) Mod (4*4)=20 Mod 16=4
i=14のとき、iii=(ii+i) Mon (n*n)=(7+14) Mod (4*4)=21 Mod 16=5
i=15のとき、iii=(ii+i) Mon (n*n)=(7+15) Mod (4*4)=22 Mod 16=6
つまり、7,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6と動いていって、
始まりがランダムなのにすべての場合を網羅しています。
ii=9なら、9,10,11,12,13,14,15,0,1,2,3,4,5,6,7,8です。
皆さん、その他でもトレースして始まりが違っていても必ず漏れなく重複なく再現できることを確認して下さい。
ランダム度を上げるための次のようにしても問題なことを確認して下さい。
iii = (ii + 3 * i) Mod n * n
(3の部分はn*nと互いに素なら何でもよいのです。aとbが互いに素とは、aとbが1以外の公約数をもたないことをいいます。
例えば、n=5とき、すなわちn*n=25の場合は、それと互いに素な整数は
1,2,3,4,6,7,8,9,11,12,13,14,16,17,18,19,21,22,23,24です。
25=5*5ですから、25と互いに素な整数は5で割り切れない整数=5の倍数でない整数です。)
i=0のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*0) Mod (4*4)=7 Mod 16=7
i=1のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*1) Mod (4*4)=10 Mod 16=10
i=2のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*2) Mod (4*4)=13 Mod 16=13
i=3のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*3) Mod (4*4)=16 Mod 16=0
i=4のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*4) Mod (4*4)=19 Mod 16=3
i=5のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*5) Mod (4*4)=22 Mod 16=6
i=6のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*6) Mod (4*4)=25 Mod 16=9
i=7のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*7) Mod (4*4)=28 Mod 16=12
i=8のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*8) Mod (4*4)=31 Mod 16=15
i=9のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*9) Mod (4*4)=34 Mod 16=2
i=10のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*10) Mod (4*4)=37 Mod 16=5
i=11のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*11) Mod (4*4)=40 Mod 16=8
i=12のとき、3 * iii=(ii+3 * i) Mon (n*n)=(7+3*12) Mod (4*4)=43 Mod 16=11
i=13のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*13) Mod (4*4)=46 Mod 16=14
i=14のとき、iii=(ii+3 * i) Mon (n*n)=(7+3*14) Mod (4*4)=49 Mod 16=1
i=15のとき、3 * iii=(ii+i) Mon (n*n)=(7+3*15) Mod (4*4)=52 Mod 16=4
で結局7,10,13,0,3,6,9,12,15,2,5,8,11,14,1,4と動きます。
これも漏れなく重複もないことを確認しましょう。
すごいでしょう。一見ランダムな動きに見えますが、実は規則的に動いていていますね。
でも、0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15で試すより、ずっとランダム度が上がっていますね。
始まりがランダムだし、規則的とはいえ動きも複雑だからです。
iii = (ii + ・ * i) Mod n * nとRandomize (・)のそれぞれの・の部分の数字を工夫すれば、6次魔方陣でも作れるようになります。
しかし、その実験も何千回も繰り返さなければなりませんので、実験自体を自動化することを考えてください。
たとえば、1000回試行錯誤を繰り返して、1個も出来なければ次の場合を試すようにするなどです。
・ と・ を2次元For文に対応させればできます。
試行錯誤の数を数えるためには、もちろんグローバル変数を用意しなければなりませんね。
自動実験のコードを次話で示してみたいと思います。
第5話へ 第7話へ
VBA講義第1部へ
vc++講義へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
数学研究室に戻る