fx-5800P:変数アクセス、比較・論理演算、条件分岐の速度比較

追記: 2014年12月13日

fx-5800PCasio Basic でプログラムを書いていると、コマンドや命令の使い方で、処理速度が大きく異なることに気づきます。

条件分岐(If 文や ⇒ 命令)、ループ (Do、While For)については以前調べています。
 ⇒ fx-5800P コマンドの処理速度【再編集】


fx-5800P の Casio Basic では配列変数を使えて便利ですが、これを使うと処理速度が大きく低下することが経験的に分かっています。

そこで、配列変数と同様な使い方のできるリストと行列を含めて、これらの処理速度を調べてみます。比較のために通常変数も併せて調べます。

fx-5800P 搭載の Casio Basic には、プログラムで変数として使えるものに、以下があります。
 ・通常変数: AZ の 26 個
 ・配列変数: Z[ ]
 ・リスト: List X[ ]List Y[ ]Freq[ ] (要素数は最大199)
 ・行列: Mat A[ ] (行列名に AZ が使える、要素数は、行・列それぞれ最大10)

論理演算(And、Or、Not)も体感的に重い処理だと分かっているので、比較演算(=、≠、<、>、≦、≧)と合わせて速度を調べてみます。



測定方法

測定し易いようにループで1000回実行させ、スマートフォンのストップウォッチアプリで、時間を計ります。
測定用のプログラム ST (Speed Test) は、以下のようにします。

・プログラム名ST xxxx (xxxx は計測対象が分かるような表現にする)

・プログラム
[必要な初期設定]
1000→A
"ST:xxxx"◢
Lbl 0
[測定対象]
Dsz A
Goto 0

必要な初期設定の後、出力命令  でプログラムは一旦停止。[EXE] キーを押すと同時にストップウォッチをスタート。
ループが1000回まわって、プログラムが終了すると画面表示が変わるので、そのタイミングでストップウォッチを止める。

但し、fx-5800P を使っていて、処理速度の個体差や、バッテリーLOW時の速度低下(電池を入れ替えると速度が上がる)などでの速度差を体感しています。さらに、fx-5800P ではクロック発生用に比較的精度のある発振子使っていない可能性があり、クロックが環境条件や電池の電圧の影響を受ける可能性がある、との情報を頂いております。⇒ sentaro様のコメント

従って、ここでの測定値は絶対値として評価することに意味はありません。基準ループとの相対的な処理時間差に着目し、その目安として測定値(ミリ秒)を用いることにします。

測定は5回行って、最大値と最小値を外し、残り3つの値の平均を計算して測定結果とします。なお私の反射神経では、小数点一桁目までは比較的再現性が高いことから、小数点1桁目までを有効数字として使い、小数2桁以下は切り捨てます。



基準ループ

1000→A
"ST: L-G"◢
Lbl 0
Dsz A
Goto 0


基準ループ測定結果: 5.9

以前、fx-5800P コマンドの処理速度【再編集】 では、上記のプログラムの最後に "DONE"◢ があります。そこでこの表示を加えたものを今回測定すると、6.1 秒 でした。以前の記事を書いた時の測定時結果が 6 秒で、前回と今回の速度差は、"DONE"◢ 表示によるものと考えらます。今回の測定での表示による速度差が 0.2 秒 なので、fx-5800P のクロック変動および測定誤差を考えると、今回の基準ループの測定結果は妥当と考えて良さそうです。

前回測定 (秒)今回測定 (秒)
"DONE"◢ 有り66.1
"DONE"◢ 無し---5.9

さて、測定対象を含んだプログラムの測定結果から基準ループ測定結果を引き算して、測定対象の処理時間を求めます。
[測定結果 (秒)] - 5.9 秒 = [測定対象の処理時間 (秒)]

これは、1000回繰り返した結果なので、1000 で割って一回あたりの処理時間 (ミリ秒) を計算します。



通常変数

先ずは、通常変数のアクセス速度を調べます。

1000→A:0→B
"ST:B"◢
Lbl 0
A→B
Dsz A
Goto 0


測定結果: 11.3 秒

[測定結果] - [基準ループ測定値] = [目的の処理時間] なので、
通常変数アクセス時間: 11.3 - 5.9 = 5.4 秒
これは、1000回実行した時の時間なので、

通常変数アクセス時間: 5.4 ミリ秒



配列変数

配列変数からの読み出しと書き込みの両方を調べました。

配列変数読み出し
0→DimZ
10→DimZ
1000→A:0→B
"ST:Z[ ] READ"◢
Lbl 0
Z[2]→B
Dsz A
Goto 0


測定結果: 28.6 

配列変数読出し時間: 28.7 ミリ秒


配列変数書き込み
0→DimZ
10→DimZ
1000→A
"ST:Z[ ] WRITE"◢
Lbl 0
A→Z[2]
Dsz A
Goto 0


測定時間: 27.9 ミリ秒

配列変数書込み時間: 22.0 ミリ秒

配列変数は、読み出しよりも書き込みが若干速いようです。これは予想外です。
配列変数へのアクセスは、通常変数の4倍弱の時間がかかることが分かりました。
速度を要求するところでは、配列変数へのアクセスを極力減らすべきです。



リスト

Casio Basic には、統計計算を行うために List が用意されています。
List は、1項目あたり、List X[ ]List Y[ ]List Freq[ ] と3つの配列が対応し、それぞれの配列の要素数は最大199です。
言い換えれば、1つの要素インデックス K に対して、List X[K]List Y[K]Freq[K] の3つの配列が使えるので、便利そうです。

XYFreq いずれも処理速度は同じと思われるので、測定には List X[ ] を使い、読み出しと書込の両方を調べました。

List 読み出し
ClrStat
{0,0,0,0,0,0,0,0,0,0}→List X
1000→A:0→B
"ST:LIST READ"◢
Lbl 0
List X[2]→B
Dsz A
Goto 0


測定結果: 31.0 秒

リスト読み出し時間: 25.1 ミリ秒


List 書き込み
ClrStat
{0,0,0,0,0,0,0,0,0,0}→List X
1000→A
"ST:LIST WRITE"◢
Lbl 0
A→List X[2]
Dsz A
Goto 0


測定結果: 31.2 秒

List 書き込み時間: 25.3 ミリ秒


List は、読み出しより書き込みに時間がかかるようです。
List へのアクセス時間は、配列変数よりも少し時間を要することが分かりました。
List の利便性は魅力がありますが、List を使うくらいなら、配列変数を使った方が少しは処理が速いことが分かります。


いずれにせよ、高速処理が必要なところでは List へのアクセスを最小限に抑えるのが良いことが分かります。



行列

fx-5800P の Casio Basic では正式に行列をサポートしていませんが、実際は使えます。
行要素、列要素それぞれ最大10です。言い換えれば、最大で、要素10の10次元配列が使えるわけで、処理内容に応じては大変便利なものです。行列についても、読み出しと書き込みの両方で測定しました。

行列読み込み
ClrMat
[[0,0,0,0,0,0,0,0,0,0]]→Mat A
1000→A:0→B
"ST:MAT READ"◢
Lbl 0
Mat A[1,2]→B
Dsz A
Goto 0


測定結果: 32.8 秒

行列読み出し時間: 26.9 ミリ秒


行列書き込み
ClrMat
[[0,0,0,0,0,0,0,0,0,0]]→Mat A
1000→A
"ST:MAT WRITE"◢
Lbl 0
A→Mat A[1,2]
Dsz A
Goto 0


測定結果: 34.3 秒

行列書き込み時間: 28.4 ミリ秒


行列は、読み出しよりも書き込みに若干時間がかかるようです。
行列のアクセス時間は、List よりもさらに時間がかかることが分かります。
速度を要求する場合は、どうしても必要性がある場合を除いて、使わないのが良いことが分かります。


以上、配列として使える、配列変数、リスト、行列 について調べた結果は、通常変数に比べて4倍程度のアクセス時間がかかることが分かり、速度を要求する場合には、極力アクセス数を減らすようなプログラムの書き方が必要なことが、明確になりました。



続いて、論理演算と比較演算の処理速度を調べます。

論理演算

fx-5800P の論理演算子には、And、Or、Not があります。いずれの処理速度も同等だと考え、測定には And を使います。

1000→A:0→B
"ST:LOGIC"◢
Lbl 0
A And B
Dsz A
Goto 0


測定結果: 15.9 秒

論理演算処理時間: 10.0 ミリ秒

論理演算1回だけの処理時間としては、短いとも長いとも言えないでしょう。しかし論理演算を多用すると、プログラムの実行速度が大きく損なわれることが分かりました。速度を要求する場合は、論理演算を極力控えた方がよさそうです。



比較演算

fx-5800P の Casio Basic の比較演算子には、=<> があります。
いずれの処理速度も同等だと考え、測定には を使い、[変数]≠[変数]、と [変数]≠[数値] の測定を行います。

変数との比較演算
1000→A:0→B
"ST:COMP B"
Lbl 0
A≠B
Dsz A
Goto 0


測定結果: 15.6 秒

変数との比較演算時間: 9.7 ミリ秒


数値との比較演算
1000→A
"ST:COMP 2"◢
Lbl 0
A≠2
Dsz A
Goto 0


測定結果: 17.4 秒

数値との比較演算時間: 11.5 ミリ秒


変数との比較演算よりも数値との比較演算に時間がかかるのは、興味深い結果です。
比較演算を行う時は、即値(数値)を使うのではなく、変数を利用するほうが処理が速くなることが分かります。

論理演算で即値を使うケースとしては、If A=0 といった処理をよく使います。
この場合は、0→C としておき、If A=C とする方が処理が速いわけで、条件分岐を多く使う場合は特に効果があります。
一方、If A≠0 とする場合は、迷わず If A とすべきでしょう。



そこで、一連の測定を行ったついでに、同じ環境条件、電池消耗条件で、If 文の処理速度も測定してみて、今回の一連の測定結果の中で、相対的にどの位置にくるのかを調べてみます。

If A≠B

1000→A:0→B
"ST:ID A B"◢
Lbl 0
If A≠B:Then
Dsz A
Goto 0

IfEnd


測定結果: 17.9 秒

If A≠B の処理時間: 12.0

この処理時間には、比較演算 A≠B が含まれているので、変数との比較演算の 9.7 ミリ秒がこの処理の多くを占めていることが分かります。


If A≠0

1000→A
"ST:IF A 0"◢
Lbl 0
If A≠0:Then
Dsz A
Goto 0

IfEnd


測定結果: 19.6 秒

If A≠0 の処理時間: 13.7 ミリ秒

B=0 の B を使ったIf 文よりも 即値 0 を使った If 文の方が 1.7ミリ秒時間がかかりますが、比較演算の変数と即値での違いの 1.8 ミリ秒に近いことが分かります。If 文では、変数を使った速い比較演算を行う方が良いことが明かです。 これは、面白い結果です。


If A

ここまでみてくると、変数が真が偽かの判定のみの場合が気になります。

1000→A
"ST:IF A"◢
Lbl 0
If A:Then
Dsz A
Goto 0

IfEnd


測定結果: 12.1 秒

If A の処理時間: 6.2 ミリ秒


比較演算を使わないと、処理速度が大幅に向上することが、今回も確認されました。


A⇒

If A よりも A⇒ の処理が速いことは既に分かっています。今回の一連の測定で、相対的にどの位置に来るのか調べて見ました。

1000→A
"ST:JUMP"◢
Lbl 0
Dsz A

A⇒
Goto 0


測定結果: 10.0 秒

A⇒ の処理時間: 4.1 ミリ秒

とても速い結果となりました。比較演算がなく、さらに IfEndへのラベル検索動作も無いことが、この結果を説明するのだと思います。


A≠B⇒ [2014/12/13 追記]

では比較演算式と条件分岐 ⇒ の組み合わせは、どうなるでしょうか?

1000→A:0→B
"ST:COMP JUMP"◢
Lbl 0
Dsz A

A≠B⇒Goto 0


測定結果: 15.9 秒

A≠B⇒ の処理時間: 10ミリ秒

比較演算が含まれますが、それでも If A≠B よりも 2 ミリ秒速いことが分かりました。条件分岐した結果の処理がコマンド/命令1つの場合は、A≠B⇒ を使う方が処理が速いことが分かります。


If A Else

1000→A:0→B
"ST:IF A ELSE"◢
Lbl 0
If A:Then

Dsz A
Goto 0

Else
IfEnd


測定結果: 13.1 秒

If A Else の処理時間: 7.2 ミリ秒

条件ジャンプ命令 を2つ使うよりも、If A Else を使った方が、間違いなく速いことが分かります。



テキスト表示 [2014/12/12 追記]

ダイナミックに数値の変化を表示するような場合は、表示速度のプログラム全体への影響が大きくなります。そこで Locate コマンドによる表示の速さを測定してみます。

1000→A
"ST:Locate"◢
Lbl 0
Locate 1,2,A
Dsz A
Goto 0


測定結果: 26.3 秒

Locate の処理時間: 20.4 ミリ秒

今回評価した中で、Locate コマンドによるテキスト表示は相対的に重い処理であることが分かります。



今回の結果を表にまとめます。

これまで感覚的に思っていたことの定量的な裏付けがとれました。
今後はこれを参考にして、速い処理が必要な時の指針にしようと思います。

表 fx-5800P Casio Basic 処理時間の比較
処理内容処理時間 (ミリ秒)
A⇒4.1
通常変数アクセス5.4
If A6.2
If A Else7.2
比較演算(変数)9.7
A≠B⇒10.0
論理演算10.0
比較演算(数値)11.5
If A≠B (変数)12.0
if A≠0 (数値)13.7
テキスト表示 (Locate)20.4
配列変数書き込み22.0
配列変数読み出し22.7
リスト読み出し25.1
リスト書き込み25.3
行列読み出し26.9
行列書き込み28.4
※ 処理時間は、基準ループからの相対差で得られたもので、絶対値に厳密性はありません。


[2014/12/12 追記]
今回作った測定用ルーチンを、全て1つのプログラムファイルにまとめて実行させるとどうなるか?
先ず、Lbl / Goto は、各測定ルーチンごとに、異なる番号を指定する必要があります。

Lbl 0 / Goto 0
Lbl 1 / Goto 1
Lbl 2 / Goto 2
   ・
   ・
   ・

試しにやってみました。
すると、予想通りに基準ループの測定値(本来 5.9 秒) が3倍に増えました。

Lbl / Goto は fx-5800P では最も速いループ構造ではありますが、Goto によりラベルを探すのにそれ相当の時間がかかっているので、探すラベルの数が増えれば目に見えて余計に時間がかかります。

Lbl / Goto を多用すると、ラベル検索のために大幅な処理速度の低下に繋がることが確認されました。

私自身、ついつい忘れそうなので、追記しておきます。





応援クリックをお願いします。励みになるので...

人気ブログランキングへ


FC2ブログランキングへ



カシオプログラム関数電卓 FX-5800P-N カシオプログラム関数電卓 FX-5800P-N
(2006/09/22)
CASIO(カシオ)

商品詳細を見る



keywords: fx-5800P、プログラミングCasioBasicプログラム関数電卓

リンク集 | ブログ内マップ


関連記事

テーマ : プログラム関数電卓
ジャンル : コンピュータ

コメントの投稿

非公開コメント

最新記事
最新コメント
カテゴリ
C# (3)
検索フォーム
Visitors
Online Counter
現在の閲覧者数:
プロフィール

やす (Krtyski)

Author:やす (Krtyski)
since Oct 30, 2013


プログラム関数電卓は、プログラムを作り・使ってナンボ!

実際に触って気づいたこと、自作プログラム、電卓プログラミングについて書いています

おもしろい・役に立つならクリックしてください。励みになります。

人気ブログランキングへ


FC2ブログランキングへ


写真: 「4駆で泥んこ遊び@オックスフォード郊外」

リンク
月別アーカイブ
Sitemap

全ての記事を表示する

RSSリンクの表示
最新トラックバック
ブロとも申請フォーム

この人とブロともになる

QRコード
QR