Casio Basic入門
誤字脱字・記載ミスや分かりにくい表現は随時追記・修正します
2017/11/03
追記修正 2017/11/05
4. CasioBasicを使ってみる(続き)
Chapter 10 - 中級◆ Chapter 10 の目標: 3桁区切り出力 - 汎用サブルーチンの作成前回:
Casio Basic入門55 を見る
今の
3DS の動作を調べるために簡単なデバッグ用プログラムを作って実際の動作を調べ、改善を試みます。
Chapter 10-23桁区切り出力サブルーチンの評価と改善先ず以下のようなデバッグ用プログラムを作ります。
▍デバッグ用プログラム3DS DEBUGDo
Cls
"X"?→X
"Z"?→Z
""
4→Y
Prog "3DS"
LpWhile Getkey=47このデバッグ用プログラムを fx-5800P で実行し、設定 (
X と
Z) に種々異なる値を入力し、期待通りの動作かどうかを確かめます。
1)X = 3、
Z = 1234567890 (10桁) を入力すると、3桁4行目から
1,234,567,890と出力されます。
2)では、
X = 5 とし、
Z は同じ
Z = 1234567890 (10桁) と入力すると、5桁4行目から
1234567890と3桁区切りせず出力します。3桁区切り出力だと1行16文字に収まらない場合はこのようになります (コード通り)。
3)Xを増やし、
X = 8、
Zは同じ Z = 1234567890 (10桁) とすると、8桁4行目から
123456789となり、右端の
0 が押し出されて消えています。
4)X をさらに増やし、
X = 12、Zは同じ
Z = 1234567890 (10桁) とすると、12桁4行目から
12345となり、現在のままだと問題です。
◆ 追加仕様1:
右にはみ出る場合は、X で指定した桁を無視して、右寄せで全ての桁を出力する。そこで、3DS 前半にある
エラー処理ブロック (以下) に着目し、
If X+K+I>17
Then
Locate X,Y,Z
Return:IfEnd以下のように
赤文字の1行を追加します。
If X+K+I>17
Then
X+K≥17⇒17-K→X
Locate X,Y,Z
Return:IfEnd3桁区切りすると1行16文字に収まらない時は、
X+K≥17 になり、この場合は3桁区切りしない値 (
Z) をそのまま右寄せで出力するので、出力開始桁である
X を
17-K→X で再設定します。
これを検証します。
3)'X = 8、
Zは同じ
Z = 1234567890 とすると、7桁4行目から
1234567890と出力され、期待通りの動作です。
4)'X = 12、
Zは同じ Z = 1234567890 とすると、7桁4行目から
1234567890と期待通りの出力になります。
=====
エラー処理の結果、3桁区切りだと行あふれになるので、区切り文字無しの正しい値が出力される仕様です。3桁区切りできない事を示すエラー表示の代わりです。しかし正しい値は表示します。汎用サブルーチンは控えめが良いのです。
このような控えめなエラー表示は、メインルーチン内で出力位置や桁数についての再検討を促す意味もある...といったコンセプトです。
では、11桁以上を出力する場合を調べます。
5)X = 2、
Z = 123456543210 (12桁) と入力すると、2桁4行目から
123,456,543,210と出力されます。ちょうど右端に出力されています。
6)X を1つ増やし
X = 3、
Zは同じで
Z = 123456543210 (12桁) を入力すると、3桁4行目から
1.234565432x101と出力されます。
本来、
1.234565432x1011 と表示されるべきなので、右端の1桁が押し出されて表示されていません。
出力開始桁は設定通りの3桁目。なおエラー処理ルーチンでは
Locate X,Y,Z で出力しているので、11桁以上は電卓の仕様に従って指数表示になっています。
7)X をさらに1つ増やして
X = 4、
Zは同じで
Z = 123456543210 (12桁) とすると、4桁4行から
1.234565432x10と出力され、右端の2桁が押し出されて表示されていません。
これで、新たな問題が明らかになりました。指数表示は電卓の仕様として、最大15桁です。そこで指数表示する場合 (
K≥11) 最大15桁が必ず表示されるように変更します。
◆ 追加仕様2:
エラー時の出力が指数表示になる場合 (K≥11 のとき)、15桁を確実に出力する。
fx-5800P は1行16文字なので、指数表示の出力開始桁 (
X) は1か2です。そこで、
K≥11 の場合、さらに出力開始桁が
2 を超える (
X>2) のとき
X を
2 に固定します。
具体的には、
エラー処理ブロックIf X+K+I>17
Then
X+K≥17⇒17-K→X
Locate X,Y,Z
Return:IfEndに3行(
赤文字)を追加します。
If X+K+I>17
Then
X+K≥17⇒17-K→X
If K≥11:Then
X>2⇒2→X
IfEnd
Locate X,Y,Z
Return:IfEnd検証します。
6)'X = 3、
Z = 123456543210 と入力すると、2桁4行目から
1.234565432x1011と期待通りに出力されます。
7)'X = 4、
Z は同じ
Z = 123456543210 とすると、2桁4行目から
1.234565432x1011と、期待通りに出力されます。
=====
入力桁をもっと大きくしてみます。
8)X = 3、
Z = 1234567890123456 (16桁) を入力してみると、1桁4行目から
1.23456789x1015と出力されます。
指定された動作は、1桁目から出力ではなくて2桁目の筈です。
9)X = 3、
Z = 12345678901234567 (17桁) を入力すると、
Locate コマンドで
Argument ERROR が発生します。
この問題を確認するために、エラー処理のコードを細かくみてみます。
If X+K+I>17
Then
X+K≥17⇒17-K→X
If K≥11:Then
X>2⇒2→X
IfEnd
Locate X,Y,Z
Return:IfEnd8) の場合は、
K = 16、
X = 2、
I = 4 なので、
赤文字で示した1つめ;
X+K≥17⇒17-K→Xが実行されると、
X = 1 となり、
赤文字で示した2つめ;
X>2⇒2→Xは実行されないので、
X = 1 となり、これは期待した動作でないことが分かります。
赤文字の1つめで
X が変更されたから、本来実行する必要のある
赤文字の2つめが動作しなかったと考えます。そこで、エラー処理ブロックでは、
X を一旦 変数
D にコピーしておき、赤文字の2カ所の評価結果を
D へ格納し、
Locate D,Y,Z を実行すれば、2つの評価が正しく実行されます。
一旦、エラー処理ブロックを以下のように変更します。
X→D
If X+K+I>17
Then
X+K≥17⇒17-K→D
If K≥11:Then
X>2⇒2→D
IfEnd
Locate D,Y,Z
Return:IfEndところが、このコードを
9) の17桁入力のケース (
K=17) に適用すると、まだ問題が残っていることが分かります。
もし、入力桁数が 17桁以上、つまり
K が 17 以上の時、
X+K≥17⇒17-K→Dが実行されると
D が 0以下になり、
Locate D,Y,Z で
Argument ERROR となることが確認できました。
K が
17 以上の場合は、必ず
If K≥11 の中の処理へ進むので、
X>2⇒2→D を変更してこの問題を解決します。
D→X
If X+K+I>17
Then
X+K≥17⇒17-K→D
If K≥11:Then
2→D:X<2⇒X→D
IfEnd
Locate D,Y,Z
Return:IfEnd入力が11桁以上の場合は、出力開始桁を強制的に
D = 2 にしておいて、
X<2 の時つまり 出力開始桁が1の時は例外的に
D = 1 に変更する...条件判定を
X>2 から
X<2 へ発想を逆転しました。
◆追加仕様3:入力が17桁以上のとき指数表示になるが、指定桁 X からの出力 or 右寄せ出力にする検証します。
8)'X = 3、
Z = 1234567890123456 (16桁) と入力すると、2桁4行目から
1.234565432x1011と、期待通りに動作します。
9)'X = 3、
Z = 12345678901234567 (17桁) とするとき、2桁4行目から
1.234567654321x1012と、今度も期待通りに動作します。
もう少し実験を進めます。
10)X = 1、
Z = 1234567654321 (13桁) を入力すると、1桁4行目から
1234,567,654,321と表示されます。
3DS は12桁対応なので仕方ないところです。
このままにするか、12桁を超えるとエラー処理ブロックで処理して指数表示するか、どちらが良いかは好みの分かれるところだと思います。
管理人の趣味では、汎用サブルーチンとして完成させるためには、上記のような13桁出力させずにエラー処理ブロックで指数表示させるようにプログラムを変更しようと思います。この変更は、ユーザーの趣味に合わせて実施しなくても良いかも知れません。
変更は単純で、
エラー処理ブロックに入るところの If 文を変更するだけです。
If X+K+I>17を
If X+K+I>17 Or K≥13に変更するだけです。
最後に少しだけ高速化してみます。
▍無駄な乗算処理を省略する1X106、
1X109 など
1X10 が12回使われています。12回10の乗算が使われていて、これは無駄です。12回の乗算を省略すれば速度向上に多少寄与します。なお、速度向上には無関係で、コード入力&表記上のみの話ではありますが、
1X10 の頭の
1 を全て消します(消しても正常動作します)。
▍論理演算を削減する最後のブロックをよく見ると、重複したコードがあります
Else
Locate X+K-6+(I≥3),Y, X107+X104V+U
Locate X,Y,X104D+W
Locate X+K-2+(I≥3),Y,","
Locate X+K-6+(I≥3),Y,","
I≥3⇒Locate X+K-9,Y,","
IfEnd(I≥3) が3回使われています。論理演算は 10ms 程度かかる重い処理なので、実行回数を減らすと高速化に寄与します。そこで、
X+K-6+(I≥3)→Jとして変数
J を導入し、以下のように変更すると 20ms 程度は処理時間が短くなります。
Else
X+K-6+(I≥3)→J
Locate J,Y, 1X107+1x104V+U
Locate X,Y,1X104D+W
Locate J+4,Y,","
Locate J,Y,","
I≥3⇒Locate X+K-9,Y,","
IfEnd
ここまでをまとめます。
高速3桁区切り出力・汎用サブルーチン:3DSZ=0⇒Return
Int(log(Z))+1→K
(K≥4)+(K≥7)+(K≥10)→I
X→D
If X+K+I>17 Or K≥13
Then
X+K≥17⇒17-K→D
If K≥11:Then
2→D:X<2⇒X→D
IfEnd
Locate D,Y,Z
Return:IfEnd
X103Frac(Z÷X103)→U
Int(X103Frac(Z÷X106))→V
Int(X103Frac(Z÷X109))→W
Int(Z÷X109)→D
If K≤8:Then
Locate X,Y,X108W+X104V+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,X107+X104V+U
Locate X,Y,X104D+W
Locate J+4,Y,","
Locate J,Y,","
I≥3⇒Locate X+K-9,Y,","
IfEnd次回は、もうひとつ機能を追加して、汎用サブルーチンとして仕上げる予定です。
つづく...
⇒ Casio Basic入門57 / Casio Basic入門G01 / 目次 応援クリックをお願いします。励みになるので...
keywords: fx-5800P、CasioBasic、入力ボックス, プログラミング入門、プログラム関数電卓
リンク集 | ブログ内マップ
- 関連記事
-
テーマ : プログラム関数電卓
ジャンル : コンピュータ