fx-9860GII グラフィックス - モンテカルロ法
2015/02/16
2015/02/17 修正
2015/02/22 追記
2015/02/28 追記
fx-9860GII のCasio Basic でグラフィックス表示のプログラムを作ってみようと、色々なコマンドを試行錯誤して試しています。先ずは第一段階として簡単なプログラムを作ってみました。2015/02/17 修正
2015/02/22 追記
2015/02/28 追記
以前モンテカルロ法による円周率:π を計算するプログラムを fx-5800P で作ったので、今回はこれにグラフィックス表示を追加したプログラムを fx-9860GII で作ってみることにします。
⇒ 海外コミュニティー(UCF)での近況
fx-5800P でのモンテカルロ法のプログラム
0→I:0→O
Lbl 1
Ran#2+Ran#2<1⇒Isz I
Isz O
Locate 1,1,O
Locate 1,2,4I÷O
Getkey=0⇒Goto 1
※ 上記エントリーのコメント欄での sentaro様のご指摘に基づき変更しています。
さて、このコンテカルロ法は、2 x 2 の正方形に内接する半径 1 の円を描いておき、その正方形内にランダムに点を打ってゆく時、正方形の中の点の数と円内の点の数から、円周率を求めようと言う考え方です。
・[正方形の面積] = 2 × 2 = 4
・[円の面積] = 1 × 1 × π = π
なので、
[正方形の面積] : [円の面積] = 4:π
となります。
これから、
π = 4 × [円の面積] / [正方形の面積]
となって、円周率の計算ができます。
ところで、ランダムに点を打ってゆくと、円内の点の数(I) が円の面積、正方形内の点の数(O) が正方形の面積としても良いので、円周率:π は以下のようにして求められます。
π = 4I ÷ O
上のプログラムは、この理屈で(実際は円の1/4 しか使っていませんが...)計算しています。
そこで、今回は同じ理屈で、正方形と内接円に実際にランダムに点を打ってゆく様子をグラフィックス表示しながら、πの計算値がどのように変化してゆくのかを表示するプログラムを、fx-9860GII で作ってみました。但し円全体を使うようにグラフィックスを描画します(円周率の計算は同じです)。
先ずは、プログラムを示します。
プログラム名: MONTECAR
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow -2.8,1.3,0,-1.0087,1.0087,0
0→I:0→O
Circle 0,0,1
Text 1,3,"C="
Text 7,1,"π="
Text 51,3,"(-):Stop"
Text 58,5,"AC:Quit"
Lbl 1
1-2Ran# →X
1-2Ran# →Y
Plot X,Y
X2+Y2<1⇒Isz I
Isz O
Text 1,11,O
Text 7,11,4I÷O
If Getkey=41:Then
Text 51,1,"EXE:Start"
While Getkey≠31
WhileEnd
Text 51,1," " (スペース3個)
Text 51,3,"(-):Stop " (スペース2個)
IfEnd
Goto 1
プログラム構造
[座標設定]
[初期化処理]
Lbl 1
[ランダム点の座標計算]
[ランダム点の描画]
[点の総数とπの計算値の表示]
[一端停止と停止解除の処理]
Goto 1
[2015/02/28 追記]
fx-9860GII のプログラムファイル montecar.g1m のダウンロード
まだ、fx-9860GII の Casio Basic コマンドが、メニュー階層のどこにあるのか、完全に把握しきれていないので、コマンドを探すのにチョット苦労しています。とりあえず、以下の入り口から探せばどこかにあり、最悪は [SHIFT] [4] (CATALOG) で探せば必ずあります。
・[SHIFT] [F2] (Zoom)
・[SHIFT] [F3] (V-Window)
・[SHIFT] [F4] (Sketch)
・[OPTN]
・[SHIFT] [VARS] (PRGM)
・[SHIFT] [MENU] (SET UP)
これを起動したところの画面は以下のようになります。
画面左上のCは打った点の総数、π はこの段階で計算した円周率です。
なお、画面左下に
(-):Stop
AC:Quit
と表示していて、起動直後に [(-)] キーを押してプログラムを一端停止させると、ランダムの点はまばらで、以下のようになります。
[EXE] キーを押して、一端停止を解除し、計算を続行させます。点が少し増えたところで、再び [(-)] を押して実行を止めると以下のようになります。
さらに計算を継続させると、
点の数がかなり増えています。
放置しておくと、正方形の範囲が殆ど塗りつぶされます。
C=27875 にもなっても、まだ一回も点が打たれていないところがあります。Ran# 関数が本当にランダムではないのでしょう。たまたま、円周率の値にかなり近くなっていますが、この Ran# 関数を使ったモンテカルロ法の精度は、あまり高くないと言えそうです。
本エントリーは、グラフィックス描画を試してみるのが目的なので、精度は気にしないでおきましょう。
ところで、点が次々に増えてゆくダイナミックな状態は、見ていて面白いものです。
※ この動画終了後に Functions と言う表示が出ますが、YouTube が勝手に次の動画を紹介しているだけで、本動画とは無関係ですので、無視してください。
この動画は、ノーマルで 29MHz のところ、オーバークロック 280MHz で動作させた時のものです。
描画に時間のかかるグラフィックスプログラムを作って動作確認をする時、待ち時間を短くして動作結果が速く分かるのは、便利です。時間のかかるグラフィックス描画を作る時は、オーバークロック動作をさせています。
私は、オーバークロックには以下のアドインを愛用しています。
sentaro様作成:Ftune2
オーバークロックでの動作のリスクはゼロではありませんが、このアドインは、プリセットで5つの設定があり、簡単にクロック数を切り替えられます。そして、表示や動作パラメータを確認しながらの設定変更も可能です。リスク低減の配慮がなされており、納得しながらリスクを減らせられるので愛用しています。詳しくは、以下のエントリーをご覧の上、ご興味があれば自己責任でお使いください。
⇒ fx-9860GII のオーバークロック - Ftune2 -
さて、今回のプログラムを作るにあたって試行錯誤の結果、Casio Basic でのグラフィックス描画について、いくつか気がついたことがありますので、それを紹介します。
画面のグラフィックス座標設定
グラフィックスは、横127ドット、縦63ドットのドットマトリックス液晶画面で描画します。
点を打つ時は、Plot コマンドでX座標とY座標を指定して、
Plot X,Y
の書式で点を描画します。X, Y で決まる位置のドット1つが表示されます。
Plot の入力:
[SHIFT] [F4] (Sketch) [F6] [F1] (PLOT) [F1] (Plot)
円の描画は、Circle コマンドで、円の中心のX座標、Y座標、そして円の半径を指定して、
Circle [中心のX座標],[中心のY座標],[半径]
の書式で円を描画します。
Circle の入力:
[SHIFT] [4] (Sketch) [F6] [F3] (Crcl)
今回は、円の中心が原点(X=0、Y=0)、半径 1 の円を描くので、
Circle 0,0,1
となります。
実は、fx-9860GII の Casio Basic では、グラフを描画する際には、ViewWindow コマンドで、X軸とY軸の範囲を指定することで、画面全体の座標系を決めます。これを利用すれば、例えばX軸の範囲、つまりXの最小値と最大値を -2.0 と 2.0 に設定すると座標の原点は中央に来ます。Xの最小値を -3.0、最大値を 1.0 にすれば、原点は中央から右にずれます。
ViewWindow の入力:
[SHIF] [F3] (V・WIN) [F1] (V・WIN)
ViewWindow は、グラフ用紙のようなものです。グラフ用紙に円を描き、用紙を右に移動させれば、当然ながら描いた円も一緒に移動します。
そこで、今回のプッログラムでは座標の設定を以下のようにしました。
ViewWindow -2.8,1.3,0,0-1.0087,1.0087,0
書式は、以下になります。
ViewWinow [X最小値],[X最大値],[X軸の目盛り間隔],[Y最小値],[Y最大値],[Y軸の目盛り間隔]
今回のプログラムでは、
・X最小値: -2.8
・X最大値: 1.3
・X軸の目盛り間隔: 0
・Y最小値: -1.0087
・Y最大値: 1.0087
・Y軸の目盛り間隔: 0
としています。
なお、画面のX方向(左右)は、左端のドットの中心と右端のドットの中心の距離は 126 ドット分 、これに対して左右のXの範囲は 1.3 - (-2.8) = 4.1 に相当します。
液晶上端のドット中心と下端ドット中心の距離は 62 ドット分なので、左右と同じ縮尺で上下のYの範囲を設定するには、
4.1:[Yの範囲] = 126:62
従って、[Yの範囲] = 4.1/126 × 62 = 2.017460317 なので、ここでは半分の値を使って、
・Y最小値: -1.0087
・Y最大値: 1.0087
と、上下は対称になるように設定しました。
画面の横幅(126ドット分)と縦幅(62ドット分)は厳密に 2:1 にはなっていないので、126対62になるように細かく設定することで、原点の回りに対称な円を描けました。
もしX軸とY軸の縮尺が異なると、この円は真円にならず、楕円になります。ゴムの上に円を書き、ゴムを一方向に引っ張ると円が楕円になるのと同じです。
この円の直径は 2 ですが、座標の設定で上下と右端に少し余裕を持たせていることに、お気づきでしょう。敢えて余裕を持たせています。
なお、引数の3つめと6つめのX軸とY軸の目盛り間隔ですが、これを 0 に設定してもエラーにならないので、今回は 0 としました。仮に 1 としても描画に変化がありません。以下に説明するように 座標軸の表示をしない設定(AxesOff コマンド使用)にしているので、影響が無いと思われます。
このように、fx-9860GII の Casio Basicでは、グラフィックスを描画する前にグラフの描画範囲(座標)をうまく設定するのがコツのようです。最初に ViewWindowで座標を決めれば、Plot や Circle はその座標系で描画できます。ViewWindow で座標設定が簡単にできるので、利便性が高いと思います。
但し、ブラフ表示を目的として各種コマンドが準備されていると考えるべきで、その場合は軸の名前(X や Y)の表示、グリッド表示、座標軸表示、目盛り表示、ラベル表示は今回のプログラムでは不要です。幸いなことに、これらの表示をオフにするコマンドが準備されているので、それを使います。
CoordOff
GridOff
AxiesOff
LabelOff
CoordOff の入力:
[SHIFT] [MENU] (SET UP) [F2] (COOR) [F2] (Off)
GridOff の入力:
[SHIFT] [MENU] (SET UP) [F3] (GRID) [F2] (Off)
AxesOff の入力:
[SHIFT] [MENU] (SET UP) [F4] (AXES) [F2] (Off)
LabelOff の入力:
[SHIFT] [MENU] (SET UP) [F5] (LABL) [F2] (Off)
テキスト表示
fx-5800P で作ったプログラムのように、打った点の数と円周率π の計算値を画面表示させます。
Locate コマンドを使うと、画面がちらつきます。Locate や " " (出力)命令などのテキスト表示の時にはグラフィックスが表示されず、グラフィックス表示の時にはテキストが表示されません。結果的にテキスト表示とグラフ表示が頻繁に切り替わるので、表示がちらつきます。テキスト表示とグラフィックス表示では異なるRAMを使っていると思われ、同時表示の方法がまだ見つかっていません(できないかも知れません)。
Text の入力:
[SHIFT] [F4] (Sketch) [F6] [F6] [F2] (Text)
Text の書式:
Text [文字の左上のドットのY座標],[文字の左上のドットのX座標],[表示内容]
※ 表示内容には、数値、変数、式、戻り値のある関数が使えます(Locate と同様)
一方、Locate の書式は、Locate [X座標],[Y座標],[表示内容]
なので、座標指定のXとYが互いに逆になっています。
なお、Text コマンドで表示される文字や数字は、Locateコマンド や " "(出力)命令 のような見やすいフォントを使った表示ではなくて、液晶のドットを使った単純な文字表示です。そして、1文字の表示で使う縦横のドット数が異なりますので、表示位置のY座標とX座標は文字に合わせて微調整しました。
数字は、縦5ドット、横3ドットのようですが、小さな数字も使えるので、その場合は文字に合わせる必要があります。一方で、表示の位置は Locate コマンドのように縦横の位置が決まっていないので、好きな位置に表示可能な利点もあります(面倒ですが...)。
ランダムな点の位置計算と描画
ランダムな点を Plot X,Y で表示させています。
fx-5800P で作ったプログラムでは、ランダムな点の座標(X,Y) のXとYは、いずれも 0~1 の範囲の正の数としていました。
今回は、グラフィックスの見栄えを考えて、半径1の円に外接する1辺が 2 の正方形の範囲全体にランダムに点を打つようにしています。従って、X と Y は、それぞれ -1 ~ +1 の範囲の値にしたいわけです。
そこで、一旦 Ran# 関数で、0~1 の値を得るまでは同じですが、これを 2 倍して、1 から引き算することで、-1 ~ +1 を算出するように変更しました。
1-2Ran# →X
1-2Ran# →Y
次に、点(X,Y) が円の中に入っているかどうかは、
X2+Y2<1
で判定し、これが正しい時に 円内の点の数 I を1つ増やす処理を行っています。
X2+Y2<1⇒Isz I
X と Y は、必ず -1 ~ +1 の間の数なので、必ず 2x2 の正方形の中の点です。そこで、無条件に Isz O で1つ増やす処理にしています。また、点は 必ず 2x 2 の正方形内に打たれることが、上記から保証されるので、描画範囲を決める座標設定 (ViewWindowコマンド) で、2 x 2 よりも少し広い範囲に設定しても問題がなく、見栄えが良くなるわけです。
打った点の総数やπの計算値の表示には Text コマンドを使って、以下のようにグラフィックス画面に表示します。
初期表示の部分で、
Text 1,3,"C="
Text 7,1,"π="
とし、Lbl 1/Goto 1 ループの中では、点1を1つ打つたびに、以下の表示を行います。
Text 1,11,O
Text 7,11,4I÷O
プログラム操作に関する部分
[(-)] キーを押した時、プログラムを一旦停止させ、[EXE] キーで一旦停止を解除する部分、それに伴う表示の変更は、以下のようにしました。
[(-)] キー(キーコード41)が押された時の必要な処理を行うので、
If Getkey=41:Then
[必要な処理]
IfEnd
としました。
プログラム全体は、Lbl 1 / Goto 1 で無限ループになっていて、If Geykey=41 はループが回るたびに実行されるので、上記のようにできます。
[必要な処理] については、 [EXE] キー(キーコード31)が押されるまでループを回し続けてプログラムが先に進むのを防ぎ、これが押されたら次へ進む、と言うロジックにしています。
表示の変更も織り込みました。
If Getkey=41:Then
Text 51,1,"EXE:Start"
While Getkey≠31
WhileEnd
Text 51,1," " (スペース3つ)
Text 51,3,"(-):Stop " (スペース2つ)
IfEnd
スペースは、上書きして前の表示を違和感なく消すために使っています。
[2015/02/27 修正]
当初、[EXE]のトグル操作で一旦停止と解除を実装していて、そのために以下の赤文字の2行を入れていました。
If Getkey=31:Then
Text 51,1,"EXE:Start"
While Getkey
WhileEnd
While Getkey≠31
WhileEnd
Text 51,1,"EXE:Stop"
IfEnd
その後、グラフィックス以外のコードを単純化するために今回の仕様に変更しましたが、その際不要なコード2行を削除し忘れていました。
今回のプログラムを作ってみて分かったことは、グラフィックス描画の前に、画面全体の座標設定(座標変換)を ViewWindow コマンドで行うと、この座標系で Plot や Circle コマンドによる点や円の描画が楽にできるということです。
テキスト表示も Text コマンドが使えて、Locate コマンドよりも柔軟性が高いことも分かりました。但しフォントが少しお粗末ですが...
実は、今回のプログラムの ViewWindow コマンドの部分を、以下の2行に置き換えるだけで(他の部分の変更無しで)、ほぼ同じように正常動作します。
ViewWindow -20.85,19.35,0,-10.05, 10.05,0
Factor 10,10
これについては、もう少し調べたいことがあるので、とりあえずメモ代わりにここに置かせてもらいます。
[2015/02/22 追記]
グラフィックス描画速度について
今回の Casio Basicプログラムとほぼ同じロジックを使って、sentaro様が Add-in プログラムを作ってくださいました(コメント欄参照)。そこで、画面描画もほぼ同じになるように改造させて頂きました。実行速度に大きな違いはありませんが、add-in 作成の練習を兼ねて改造させてもらいました。
⇒ sentaro様作成の Add-in、montecar.g1a: ダウンロード
⇒ 私が手を入れた Add-in、monteca2.g1a: ダウンロード
※ ダウンロードした ZIP ファイルには、add-in プログラムと Casio SDK でビルド可能なソースファイルが含まれています。
Add-in プログラム monteca2.g1a を fx-9860GII に転送すると、[MENU] キーで現れる MAIN MENU 画面に、この Add-in が表示されています(画面の右下)。
なお、この add-in には、実行時間を計測するルーチンが組み込まれていて、ストップウォッチ無しでも実行時間の計測ができるようになっています(この部分が sentaro様オリジナルの非常に役立つルーチンで、(ここだけがオリジナルの Casio Basic プログラムと異なります)。
Casio Basic プログラムと、ほぼ同じ画面になっていることが分かります。なお、 t= 7.04s と実行時間が表示されています。
やはりC言語で作るプログラムは Casio Basic よりも圧倒的に速いです。どれぐらい速いか、見てみましょう。
これは、ノーマルクロック (29MHz) でのものです。
動作モードメニューで、
F1:MonteCarlo 1/1
F2:MonteCarlo 1/10
F3:MonteCarlo 1/100
F5:MonteCarlo bench
F6:MonteCarlo bench 2
と表示され、上から順に [F1] から順に [F6] まで実行しています。
オーバークロック (280MHz) では、さらに速くなります。
[F1] から順に [6] まで5つの動作モードで動作しています。圧倒的速さを実感できます。
さて、fx-9860GII のノーマルクロック 約29MHzと、オーバークロックした約 280MHz も併せて試した結果を以下に示します。
測定は、点の総数が100個程度になったら実行を止めて、その時間と点の総数を5回測定。これから点100個あたりの時間を計算し、最大値と最小値を取り除き、残る3回の平均を計算して、ループ1回あたりの実行時間を得ました。Add-in は、複数の動作モードから、オリジナルの Caso Basic に最も近い [F1] のモードを使用しました。
プログラム | Casio Basic | Add-in | ||
動作クロック (MHz) | 約29 | 約280 | 約29 | 約280 |
ループ1回の実行時間 (ミリ秒) | 278 | 43.6 | 21.0 | 7.40 |
速度比率 (全体) | 1 | 6.4倍 | 13.2倍 | 37.6倍 |
速度比率 (Basic と Add-inの比較) - 280MHz | --- | 1 | --- | 5.9倍 |
速度比較 (29MHz と 280Mhzの比較 - Add-in | --- | --- | 1 | 2.8倍 |
・ ノーマルクロックでは、Casio Basic のままオーバークロックするよりも、C言語によるAdd-in の高速化が顕著(2倍)です。
・ オーバークロックの効果は、C言語による Add-in よりも Casio Basicの方がその効果は顕著(約2倍)です。
今回のように、画面を埋め尽くすようなグラフィックス描画を高速に動作させたい場合は、C言語による Add-in を考えるべきです。
しかしCasio SDK によるプログラム作成の敷居の高さを考えると、次善の策として Casio Basic で作ってオーバークロックと言う方法があります。
そして、fx-9860GII USB POWER GRAPHIC2 (現行機種) は、他のグラフ関数電卓の現行機種と比べて、オーバークロックツール Ftune2 で最大限の効果が得られます(コメント欄参照)。モノクロ表示ですが、fx-9860GII の価値は高いと言えます。
Casio Basic 搭載のグラフィックス機能は、グラフ描画機能に特化したもので、グラフ作成のための多彩な機能がある一方で、描画点数の多いグラフィックス表示は、かなり遅いことが定量的にわかりました。
なお、この測定のために、円の描画と必要な表示の後に一端停止し、[EXE] キーで停止を解除するように Casio Basic プログラムを変更しました(下記参照、追加した部分を赤文字で示す)。Add-in プログラムの時間測定が、初期描画終了後、ループに入る手前で測定開始するようになっているので、それに合わせました。
※ fx-9860GII に転送して使える Montecar.g1m のダウンロード
fx-9860GII プログラム: Montecar
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow -2.8,1.3,0,-1.0087,1.0087,0
0→I:0→O
Circle 0,0,1
Text 1,3,"C="
Text 7,1,"π="
Text 51,3,"EXE:Start"
Text 58,5,"AC:Quit"
While Getkey≠31
WhileEnd
Text 51.1." "
Text 51,3,"(-):Stop "
Lbl 1
1-2Ran# →X
1-2Ran# →Y
Plot X,Y
X2+Y2<1⇒Isz I
Isz O
Text 1,11,O
Text 7,11,4I÷O
If Getkey=41:Then
Text 51,1,"EXE:Start"
While Getkey≠31
WhileEnd
Text 51,1," " (スペース3個)
Text 51,3,"(-):Stop " (スペース2個)
IfEnd
Goto 1
応援クリックをお願いします。励みになるので...
keywords: fx-9860GII、CasioBasic、プログラム関数電卓
リンク集 | ブログ内マップ
- 関連記事
-
- fx-9860GII への移植 - 厄介な 旧来の命令 2017/06/29
- fx-9860GII グラフィックス - モンテカルロ法 2015/02/22
- fx-9860GII への移植 - ピタゴラス数 2014/12/14
- fx-9860GII への移植 - 素因数分解 2014/12/08