Casio Basic入門
誤字脱字・記載ミスや分かりにくい表現は随時追記・修正します
追記修正 2017/10/25
4. CasioBasicを使ってみる(続き)
Chapter 9 - 初級前回:
Casio Basic入門52 を見る
◆ Chapter 9 の目標: 簡単な換算プログラム - 入力ボックスの活用
Chapter 9-3
fx-5800P での3桁区切り表示を高速化する
前回作った3桁区切りできる複利計算プログラムを再掲します。
・サブルーチン: 3DIGIT
・メインルーチン: COMPINT2
ファイル名: 3DIGIT
Z=0⇒Retuen
Int(log(Z))+1→D
D-3Int(D÷3)→F
For 1→I To D
Int(Z÷10^(D-I))→C
Locate X+I-1,Y,C
Z-C10^(D-I)→Z
If I-3Int(I÷3)=F
Then Isz X
I<D⇒Locate X+I-1,Y,","
IfEnd
Next
ファイル名: COMPINT2
Locate 1,1,"1-C:"
Locate 1,2,"2-R:"
Locate 10,2,"3-Y:"
Locate 1,3,"TOTAL"
Locate 1,4,"MONTH"
0→B:0→R:0→N:0→T:0→M
Do
0→K:Do
Getkey→K
LpWhile K=0
K=73⇒Break
If K=35
Then
5→X:1→Y:8→D:1→E
Locate X,Y," " (スペース11個)
Prog "INP":Z→B
Prog "3DIGIT"
Else If K=36
Then
5→X:2→Y:4→D:1→E
Prog "INP":Z→R
Else If K=37
Then
14→X:2→Y:3→D:1→E
Prog "INP":Z→N
IfEnd:IfEnd
IfEnd
If BRN:Then
Int(B(1+R÷100)^(N))→T
Locate 7,3," " (スペース10個)
T→Z:7→X:3→Y
Prog "3DIGIT"
Int(T÷N÷12)→M
Locate 7,4," " (スペース10個)
M→Z:7→X:4→Y
Prog "3DIGIT"
IfEnd
LpWhile 1
Cls
Locate 7,2,"BYE!"
▋前回のプログラムと高速化の試み
以下のように、3桁区切りで表示ができましたが、
左から右へ、パラパラと表示されて時間がかかります。
今回のプログラムで一番動作時間がかかるのは、Locate コマンドです。そして、For ループで Locate が何度も実行されているので、表示に時間がかかると考えています。このプログラムでは、例えば 12345678 を表示するには Locate を10回実行しています。
そこで、表示を高速化するには、Locate が実行される回数を減らせば良いことになります。
私が最初に考えたのは、例えば 12345678 を 12,345,678 として表示するために Locate を使って、
1) 12 を表示
2) ,(コンマ)を表示
3) 345 を表示
4) ,(コンマ)を表示
5) 678 を表示
つまり、Locate 実行の回数が10回から5回へ半減しますので、良さそうです。実際に作ってみると、問題がありました。
それは、例えば 139096 を3桁区切りにすると 139,096 となるべきところ、そうはならないバグです。文字列を使えない fx-5800P で数値を出力する時に避けられない問題でした [2017/11/06 校正]。
上の考え方だと
1) 139 を表示⇒問題なし
2) ,(コンマ)を表示⇒問題なし
3) 096 を表示⇒問題発生
Locate コマンドで 数値 096 を表示すると 96 になってしまいます。
つまり、3桁区切りの表示が 139,96 と妙なことになります。
fx-5800P Casio Basic では文字列を扱うコマンドが無いので、096 を一旦文字列に変換して Locate で表示することができません。
ただし、この問題は簡単に解決できます。096 は、3桁でなくて2桁なので、3桁未満の時は文字 "0" を先に表示してから3桁未満の数値を表示すれば良いだけです。
あるいは、先に文字列 "000" を表示した上に 必要な桁から2桁か2桁の数値を上書きする方法もあります。
過去の Casio Basic 入門でも、この方法は使っています。
但しこれらの方法では、ある所定の数値の場合に Locate の実行回数を減らすことができずい、本質的な解決策とはならない中途半端な方法だと考えました。
そんなわけで、表示に時間がかかるものの、ロジックとしては素直でコンパクトな前回のプログラムを紹介したわけです。
▋3桁表示の高速化
sentaro 様から面白いロジックをご提案頂き、それを紹介したいと思います。これは、3桁区切りをチョット巧妙に実現するものです。そのロジックやプログラムの実装方法は初級というよりも中級に入るかも知れません。
例えば 12345678 を表示する前に、コンマが入るところに 0 を入れた数値を作って、
1203450678
として、一旦この数値を Locate で表示します。
次に、コンマが入るところの 0 を ,(コンマ)で上書きして(Locate コマンド使用)、
12,345,678
とすれば良い...といった考え方です。私には思いつかなかった面白いものです。
この8桁の数値を3桁区切り表示する時の Locate 実行回数は3回になって、激減します(前回のプログラムだと10回実行)。
このロジックだと、上で問題が発生した 139096 の場合は、一旦 1390096 に変換して、この数値を Locate で表示。続いてコンマが入るべき 0 の位置に Locate で , (コンマ)を上書きするので、
139,096
と正しく表示されます。
なかなかよく考えられたロジックですね。
前回作ったプログラムでは、Locate を7回実行するところ、2回で済むので、表示が大いに高速化されます。
▋新ロジックの実装
そこで、3桁区切り表示を行うサブルーチン 3DIGIT を 3DIGIT2 とします。
メインルーチンは、COMPINT2 を COMPINT3 にします。
プログラムを以下に示します。
・サブルーチン: 3DIGIT2
・メインルーチン: COMPINT3
ファイル名: 3DIGIT2
Z=0⇒Retuen
Int(log(Z))+1→K
(K≥4)+(K≥7)+(K≥10)→I
Frac(Z÷1x103)×1x103→U
Int(Frac(Z÷1x106)×1x103)→V
Int(Frac(Z÷1x109)×1x103)→W
Int(Z÷1x109)→D
If K≤8:Than
Locate X,Y,1x108×W+1x104×V+U
I≥1⇒Locate X+K-2-(I=1),Y,","
I≥2⇒Locate X+K-6,Y,","
Else
Locate X+K-6+(I≥3),Y,1x107+1x104×V+W
Locate X,Y,1x104×D+W
Locate X+K-2+(I≥3),Y,","
Locate X+K-6+(I≥3),Y,","
I≥3⇒Locate X+K-9,Y,","
IfEnd
変数の説明:
入力値: Z
X座標: X
Y座標: Y
ワーク変数 U:下3桁
ワーク変数 V:中3桁
ワーク変数 W:上3桁
ワーク変数 D:最上位1桁
ワーク変数 K数値の桁数
ワーク変数 I:三桁区切り文字の数
ここで、解説を2つだけ...
▶ 青文字の( ) の部分
この ( ) は、0か1かの値になります。( ) の中が正しいなら(真ならば)1、正しくなければ(偽ならば)0になります。この性質をうまく使って計算式に中で利用しています。
▶ 赤文字 x104 の表記
これは [x10x] キーを押して入力します。
メインルーチンは、呼び出すサブルーチン名を変更するだけ...
ファイル名: COMPINT3
Locate 1,1,"1-C:"
Locate 1,2,"2-R:"
Locate 10,2,"3-Y:"
Locate 1,3,"TOTAL"
Locate 1,4,"MONTH"
0→B:0→R:0→N:0→T:0→M
Do
0→K:Do
Getkey→K
LpWhile K=0
K=73⇒Break
If K=35
Then
5→X:1→Y:8→D:1→E
Locate X,Y," " (スペース11個)
Prog "INP":Z→B
Prog "3DIGIT2"
Else If K=36
Then
5→X:2→Y:4→D:1→E
Prog "INP":Z→R
Else If K=37
Then
14→X:2→Y:3→D:1→E
Prog "INP":Z→N
IfEnd:IfEnd
IfEnd
If BRN:Then
Int(B(1+R÷100)^(N))→T
Locate 7,3," " (スペース10個)
T→Z:7→X:3→Y
Prog "3DIGIT2"
Int(T÷N÷12)→M
Locate 7,4," " (スペース10個)
M→Z:7→X:4→Y
Prog "3DIGIT2"
IfEnd
LpWhile 1
Cls
Locate 7,2,"BYE!"
3桁区切りでの表示が劇的に速くなりました。
コードを眺めて、プログラムの巧妙さを楽しんでください。
fx-5800P の Casio Basic には文字列処理の機能がありませんが、工夫次第で色々と実現できるわけで、逆に言えば Casio Basic がそれだけ高機能だとも言えますね。
つづく...
⇒ Casio Basic入門54 / Casio Basic入門G01 / 目次
応援クリックをお願いします。励みになるので...
- 関連記事
-
テーマ : プログラム関数電卓
ジャンル : コンピュータ
sentaro様
管理人のやすです。
> 最初のグラフ電卓の発売が30年以上前で、その時の搭載言語はほぼマクロと言ってもいいレベルなので、管理人様の憶測は当たっていると思います。(^^)
> 最初から高機能Basic言語を載せるのはメモリの制約等でできなかったのでしょうし、まだポケコンが進化を続けていた時代なので棲み分けという意味でも電卓用言語として必要最小限でスタートしたというところでしょうか。
FX-7000G のマニュアルがありました。
https://web.archive.org/web/20031216054750/http://www.silrun.de/casio/fx7000/manual/Chapter4.pdf
https://web.archive.org/web/20031217095639/http://www.silrun.de/casio/fx7000/manual/Chapter5.pdf
これを見ると、私が以前使っていた fx-4500PA に近い感じの Goto / Lbl でジャンプするプログラミング方法です。
この頃から :、⇒、 ?→ や ◢ が有ったんですね。
FX-502P 系列の方が遙かに柔軟なプログラミングができたので、ある意味カシオの電卓言語暗黒時代と言えるかも知れません。以前の記事の中で "中途半端な言語"で結局成功しなかった...と書いたと思います。
[追記] Casio Basic入門1で書いていました。
http://egadget.blog.fc2.com/blog-entry-50.html
ポケコン用言語と融合したことで、グラフ関数電卓向けに開発が進み、現在の Casio Basic に繋がるということがよく分かります。
面白いですね!
> 今までは大雑把な速度比較しかしてきていないので、コマンド別の速度比較はかなり興味深いです。(^^)
いずれ、まとめてみようと思います。
> fx-9860GIIは画面処理は軽さを考えると、CasioBasicでの文字列処理がかなり遅そうという感じです。(^^;
fx-CG50 では CG20 の BFC、SFC、コアクロック を速くしたけど、依然遅いわけで、ストレージメモリアクセスが伴うコマンドは、ひとくくりにして遅いと言えそうです。文字列処理は内部的に行列を使っている可能性が高そうですね (C.Baisc と同じ発想)。
管理人様、こんにちは!
>Casio Basic は本来マクロ言語として開発され、徐々に開発言語の体裁を整えてきた、という憶測です。
最初のグラフ電卓の発売が30年以上前で、その時の搭載言語はほぼマクロと言ってもいいレベルなので、管理人様の憶測は当たっていると思います。(^^)
最初から高機能Basic言語を載せるのはメモリの制約等でできなかったのでしょうし、まだポケコンが進化を続けていた時代なので棲み分けという意味でも電卓用言語として必要最小限でスタートしたというところでしょうか。
>グラフ電卓についても、各コマンドに対して、9860GII、CG20, CG50 の処理速度を調べると面白そうですね。いずれやってみようと思います。
今までは大雑把な速度比較しかしてきていないので、コマンド別の速度比較はかなり興味深いです。(^^)
>計算速度と文字列処理速度では、傾向が変わっていることが分かりますね。
Locateによる画面出力と内部処理の比重がどれくらいかということですね。
9860GIIのクロックをCG20と同じ58MHzにして計測すると、
fx-9860GII(OS 2.09)
3DS (数値処理) 7秒
3DSS (文字列処理) 17秒
CG20よりは速くCG50に近づいていきます。
fx-9860GIIは画面処理は軽さを考えると、CasioBasicでの文字列処理がかなり遅そうという感じです。(^^;
sentaro様
管理人のやすです。
> 文字列コマンドを有効に使うには数値からの変換コマンドは必須と思われるところなのでちょっと手落ち感がありますね。
> おそらく、CasioBasicでの文字列コマンドは、TI-84シリーズのTI-Basicで文字列サポートされたことへの対応と思われるのですが、TIでも初期文字列コマンドに数値から文字列への変換コマンドが無かったのでそれは必要ないと考えたのでしょう。
なるほど、そのような背景は大いにありそうですね
> とはいえ、さすがに現行のTI-84CEシリーズの最新OSでは文字列への変換コマンドが新規追加されましたので、CasioBasicでも何かしら対応しないといけないと思われるのですが、今回の3.10での追加は見送られてますね。(^^;
ということは、Casio は 教育用の様々な機能を便利にするためのマクロの役割を Casio Basic に持たせることを第一に考えていて、Casio Basic だけで完結するプログラミング言語として考えていない...と思うと現在の仕様の不十分さや取扱説明書の説明が分かる気がします。
Casio Basic は本来マクロ言語として開発され、徐々に開発言語の体裁を整えてきた、という憶測です。
> CasioBasicの文字列処理はマルチバイト文字列なので通常の文字列よりは重くなるのは仕方ないとしてもここまで遅いとは予想外でした。
以前 fx-5800P でやったようなコマンドの処理速度比較をやりました。
グラフ電卓についても、各コマンドに対して、9860GII、CG20, CG50 の処理速度を調べると面白そうですね。いずれやってみようと思います。
> CG20での結果を見るとさらに差が縮まります。
> CG20(OS 3.10
> 3DS (数値処理) 21秒
> 3DSS (文字列処理) 24秒
3機種をまとめて比較すると...
CG20 9860GII CG50
3DS (数値処理) 21秒 16秒 9秒
3DSS (文字列処理) 24秒 30秒 14秒
計算速度と文字列処理速度では、傾向が変わっていることが分かりますね。
これがストレージへのアクセス速度の変化 (CG50のSDRAM採用も含めて)によるものなのか、CG20 で文字列処理を見直して高速化したのか、調べてみたくなっています。
上の測定だけだと、SDRAM採用の効用が大きいように思われます。
> CG50はストレスに感じる部分がほとんど無くなったのが素晴らしいです。(^^)
IT機対策だけではなく、全体を見直して頑張ったのかも知れませんね。
管理人様、こんにちは!
>数値から文字列への変換コマンドが無いのは結構な欠点ですよね。
文字列コマンドを有効に使うには数値からの変換コマンドは必須と思われるところなのでちょっと手落ち感がありますね。
おそらく、CasioBasicでの文字列コマンドは、TI-84シリーズのTI-Basicで文字列サポートされたことへの対応と思われるのですが、TIでも初期文字列コマンドに数値から文字列への変換コマンドが無かったのでそれは必要ないと考えたのでしょう。
とはいえ、さすがに現行のTI-84CEシリーズの最新OSでは文字列への変換コマンドが新規追加されましたので、CasioBasicでも何かしら対応しないといけないと思われるのですが、今回の3.10での追加は見送られてますね。(^^;
>やはりそうですか...
>今のところ、sentaro様ご発案の数値処理が最速になりますよね。まさにプログラミングの醍醐味と言えますね。
>実際に計ってみるとビックリです。逆に fx-CG50の良さが光る結果となりました。
恐縮です。
CasioBasicの文字列処理はマルチバイト文字列なので通常の文字列よりは重くなるのは仕方ないとしてもここまで遅いとは予想外でした。
CG系で速度差が縮まっているのは、画面処理がかなりを占めていて、文字列処理の比重が比較的に軽くなったからかもしれません。
CG20での結果を見るとさらに差が縮まります。
CG20(OS 3.10
3DS (数値処理) 21秒
3DSS (文字列処理) 24秒
CG50はストレスに感じる部分がほとんど無くなったが素晴らしいです。(^^)
sentaro様
管理人のやすです。
> 仕様上の10桁表示を越えて15桁まで表示可能になるのがプログラムの醍醐味ですね。(^^)
はい、このあたりが面白いところですよね。
> 純正CasioBasicでは数値から文字列への変換コマンドが無いので複数桁をまとめて処理という方法も使えないですし仕方ないところでしょうか。
数値から文字列への変換コマンドが無いのは結構な欠点ですよね。
> 文字列版3DSSの高速化はLocateを減らすのと同じく文字列処理を減らすしか無さそうですが、これ以上減らすのも無理なので高速化ができそうにありません。(^^;
やはりそうですか...
今のところ、sentaro様ご発案の数値処理が最速になりますよね。まさにプログラミングの醍醐味と言えますね。
> CG50では1.5倍遅いくらいですが、fx-9860GIIだと3倍遅いので大差ですね。(^^;
実際に計ってみるとビックリです。
逆に fx-CG50の良さが光る結果となりました。
> ※文字列版3DSSのデバッグ情報です。
> この部分は、数値から文字列化の部分なので、
> -----------------------------------
> Str 1+StrMid("0123456789012345",I+1,1)->Str 1
> -----------------------------------
> これで正解ですね。
> -----------------------------------
> Str 1+StrMid("0123456789",W+1,1)->Str 1
> -----------------------------------
ありがとうございます。取り敢えず差し替えておきました。
[以下は備忘録]
数値処理版(3DS)と文字列処理版(3DSS)で速度比較する 3DSPEED を作ってみました。3桁区切りで15桁を50回出力して FINISHと表示します。
サブルーチン呼び出しで、3DS と 3DSS を書き換えて比較します。
fx版 3DSPEED:
https://egadget2.web.fc2.com/archives/fx-9860GII/3DS/3DSPEED_9860GII.html
CG版 3DSPEED:
https://egadget2.web.fc2.com/archives/fx-CG50/3DS/3DSPEED_CG50.html
管理人様、こんにちは!
高速3桁区切り、おつかれさまです。
仕様上の10桁表示を越えて15桁まで表示可能になるのがプログラムの醍醐味ですね。(^^)
で、意外にも遅い文字列版3DSSですが、ループ内でべき乗演算が2回もあるのが遅い原因かと思ったらそうでもなくて、文字列処理が遅いみたいですね。
CG50では1.5倍遅いくらいですが、fx-9860GIIだと3倍遅いので大差ですね。(^^;
文字列版3DSSの高速化はLocateを減らすのと同じく文字列処理を減らすしか無さそうですが、これ以上減らすのも無理なので高速化ができそうにありません。(^^;
純正CasioBasicでは数値から文字列への変換コマンドが無いので複数桁をまとめて処理という方法も使えないですし仕方ないところでしょうか。
※文字列版3DSSのデバッグ情報です。
この部分は、数値から文字列化の部分なので、
-----------------------------------
Str 1+StrMid("0123456789012345",I+1,1)->Str 1
-----------------------------------
これで正解ですね。
-----------------------------------
Str 1+StrMid("0123456789",W+1,1)->Str 1
-----------------------------------
sentaro様
管理人のやすです。
sentaro様のアイディアで文字列処理版を作って見ましたが、意外に遅いです。
数値処理版(3DS)と文字列処理版(3DSS)で速度比較する 3DSPEED を作ってみました。3桁区切りで15桁を50回出力して FINISHと表示します。
サブルーチン呼び出しで、3DS と 3DSS を書き換えて比較します。
fx版 3DSPEED:
https://egadget2.web.fc2.com/archives/fx-9860GII/3DS/3DSPEED_9860GII.html
CG版 3DSPEED:
https://egadget2.web.fc2.com/archives/fx-CG50/3DS/3DSPEED_CG50.html
文字列処理版の方が、使用変数を減らせるので、これが高速化できると良いのですが...
取り敢えずダウンロードリンクを設定しました。
[追記]
3DSPEED で50の簡単な比較測定結果です。電卓はいずれもノーマルクロックです。
9860GII CG50
3DS (数値処理) 16秒 9秒
3DSS (文字列処理) 30秒 14秒
おそらく ストレージメモリアクセスを伴う StrMid( で、15桁の文字列をスキャンする処理は、かなり重いのでしょう。行列やリストへのアクセスが遅いのと似た感じでしょうか?
そういえば文字列処理コマンドの処理速度比較をまだやっていませんでした。
sentaro様
fx-5800P版の高速3桁区切り を取り敢えずまとめました。
sentaro様ご提示のロジックが素晴らしいので、きちんとまとめたいと以前から思っていて、ようやくできました。
右寄せ出力に対応したのがメインですが、3桁区切りできない時でも画面からはみださないようにして汎用性を持たせました。12桁対応です。
Casio Basic入門55
http://egadget.blog.fc2.com/blog-entry-618.htmlCasio Basic入門56
http://egadget.blog.fc2.com/blog-entry-623.htmlCasio Basic入門57
http://egadget.blog.fc2.com/blog-entry-624.html次は、グラフ関数電卓への移植です。fx-5800P版を、変数を増やさずに15桁対応したものは、既に手元で日常的に使っています。
文字列処理を使うのも記事で紹介したいと思っています。
管理人様、こんにちは!
>最初のパラパラ表示版では、ここは使い方で対応してもらうようにして、きちんとやっていません。
じつは、管理人様のパラパラ表示版(ネーミングにちょっとウケました!(^^;)だと11桁以上になっても問題なく表示可能!なので12桁まで対応に修正させていただいた次第です(^^;
>せっかくなので、sentaro様の高速版とパラパラ版の両方で、表示桁管理を新しいネタとして追加してみようかな、と思います。
さらに追加ネタ?といっては何ですけど、fx-9860GIIでは文字列が使えるので、パラパラ表示版を文字列版に改造してみました。
Locateが最後の一回だけになったので、表示が遅く内部演算が速いCG10/20では高速版とあまり変わらない表示速度になる感じです。
--------------------------------------
Z->A
Int (log A)+1->D
D-3Int (D/3)->F
""->Str 1
For 1->I To D
Int (A/(10)(D-I))->C
Str 1+StrMid("0123456789",C+1,1)->Str 1
A-C(10)(D-I)->A
If I-3Int (I/3)=F
Then
I<D=>Str 1+","->Str 1
IfEnd
Next
Locate X,Y,Str 1
--------------------------------------
(CG10/20、C.Basic、さらにFD10Proでそのまま使えると思われるテキスト形式です)
>こうやって、話題が膨らむと楽しいですね(^_^)/
はい!
身近なところにプログラムのネタは転がっているということですね(^^)
sentaro様
桁オーバーフロー対応ですね。
最初のパラパラ表示版では、ここは使い方で対応してもらうようにして、きちんとやっていません。
せっかくなので、sentaro様の高速版とパラパラ版の両方で、表示桁管理を新しいネタとして追加してみようかな、と思います。
こうやって、話題が膨らむと楽しいですね(^_^)/
ありがとうございます。
管理人様、こんにちは!
3DIGIT2では10桁を超えると表示がおかしくなるので(^^;
fx-5800Pで表示可能な12桁まで対応してみました。
3DIGIT2をベースに改造です。
乗算省略形式にして、JをX桁計算のワーク変数として追加使用しています。
--------------------------------------
'ProgramMode:RUN
Int log Z+1->K
(K>=4)+(K>=7)+(K>=10)->I
Exp3Frac (Z/Exp3)->U
Int (Exp3Frac (Z/Exp6)->V
Int (Exp3Frac (Z/Exp9)->W
Int (Z/Exp9)->D
If K<=8:Then
Locate X,Y,Exp8W+Exp4V+U
I>=1=>Locate X+K-2-(I=1),Y,","
I>=2=>Locate X+K-6,Y,","
Else
X+K-6+(I>=3)->J
Locate J,Y,Exp7+Exp4V+U
Locate X,Y,Exp4D+W
Locate J+4,Y,","
Locate J,Y,","
I>=3=>Locate X+K-9,Y,","
IfEnd
--------------------------------------
(CG10/20、C.Basic、さらにFD10Proでそのまま使えると思われるテキスト形式です)
管理人様、こんにちは!
数値をまとめて処理は若干トリッキーではありますが(^^;取り上げていただきましてありがとうございます。
今回の例だとLocateの使用回数を減らすことが実行速度に直結していることがよくわかりますが、fx-5800pでも表示機構はfx-9860GIIと同様に表示コマンド毎に画面全体のLCD転送が発生しているものと推測されるので、やはり表示は最小限に抑えることが高速化のポイントになってきますね。
管理人様の一桁づつ表示は目に見える逐次処理感がプログラム的に素直でよいですし、表示のまったり感が初期の液晶電卓のような趣があって懐かしさも感じます(^^)
そして何より文字列処理の無いfx-5800Pでも3桁区切り表示が出来てしまうことがCasioBasicの優秀さを表してますね!