Casio Basic入門56

Casio Basic入門
<目次>

誤字脱字・記載ミスや分かりにくい表現は随時追記・修正します

 2017/11/03
追記修正 2017/11/05


 4. CasioBasicを使ってみる(続き)

Chapter 10 - 中級

◆ Chapter 10 の目標: 3桁区切り出力 - 汎用サブルーチンの作成

前回: Casio Basic入門55 を見る


今の 3DS の動作を調べるために簡単なデバッグ用プログラムを作って実際の動作を調べ、改善を試みます。

Chapter 10-2
3桁区切り出力サブルーチンの評価と改善

先ず以下のようなデバッグ用プログラムを作ります。

デバッグ用プログラム

3DS DEBUG
Do
Cls
"X"?→X
"Z"?→Z
""
4→Y
Prog "3DS"
LpWhile Getkey=47



このデバッグ用プログラムを fx-5800P で実行し、設定 (XZ) に種々異なる値を入力し、期待通りの動作かどうかを確かめます。


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:IfEnd


3桁区切りすると1行16文字に収まらない時は、X+K≥17 になり、この場合は3桁区切りしない値 (Z) をそのまま右寄せで出力するので、出力開始桁である X17-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) のとき X2 に固定します。

具体的には、エラー処理ブロック

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:IfEnd


8) の場合は、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,ZArgument ERROR となることが確認できました。

K17 以上の場合は、必ず 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

に変更するだけです。




最後に少しだけ高速化してみます。

無駄な乗算処理を省略する
1X1061X109 など 1X10 が12回使われています。12回1の乗算が使われていて、これは無駄です。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桁区切り出力・汎用サブルーチン:3DS
Z=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入門57Casio Basic入門G01 / 目次



応援クリックをお願いします。励みになるので...
にほんブログ村 IT技術ブログ 開発言語へ


 



keywords: fx-5800PCasioBasic、入力ボックス, プログラミング入門プログラム関数電卓

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


関連記事

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

コメントの投稿

非公開コメント

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

やす (Krtyski)

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


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

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

なお管理人はカシオ計算機の関係者ではなく、Casio Basicが面白いと感じる1ユーザーです。


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

リンク
月別アーカイブ
Sitemap

全ての記事を表示する

ブロとも申請フォーム

この人とブロともになる

QRコード
QR