プレイ日記
おちゃめ ochame_nako
数値を誤差ゼロで文字列に変換するPSTR$関数のver.2.0ができました。 PSTR$はセーブデータ作りやデバッグ用など様々な用途で活用できる便利な関数です。 PSTR$の詳しい使い方やSTR$、FORMAT$ではなぜダメなのかはコメントに書いているので、ぜひ参考にしてみてください。
14そうだね
プレイ済み
返信[1]
親投稿
おちゃめ ochame_nako
プログラムリストです。(公開キーは後述)
0そうだね
プレイ済み
返信[2]
親投稿
おちゃめ ochame_nako
プチコン3号には数値を文字列に変換するSTR$関数が標準で存在しているのにこのような自作関数を作ったのはSTR$は文字列化する場合に値が丸められてしまう場合が多いからです。 例えばA=1234567の時にSTR$(A)は1.23457e+06となります。 これは1.23457×10の6乗という意味です。 指数を使わずに表記すれば1234570となります。 
0そうだね
プレイ済み
返信[3]
親投稿
おちゃめ ochame_nako
文字列を数値に変換するにはVALを使いますが、A$=STR$(A)の時にVAL(A$)としても1234570という値になり本来の1234567という値には戻りません。 これだとセーブデータとして使うのには不安が残ります。 といっても100万未満の整数値しか扱わないならSTR$で問題ないし、STR$(A%)のように整数型変数を指定した場合には整数型で扱える-2147483648~+2147483647の範囲の整数ならば誤差無し(指数表示無し)で文字列化が可能です。 したがって、小数を扱いたいとか100億とか1兆とかの大きな数を扱いたいというのであれば問題があるというだけです。
0そうだね
プレイ済み
返信[4]
親投稿
おちゃめ ochame_nako
プチコン3号には文字列にする命令としてはSTR$の他にもFORMAT$が存在します。 Aの値が整数ならばFORMAT$("%10D",A)とすればAの値を10桁の文字列にすることができます。 小数を扱いたい場合はFORMAT$("%10.3F",A)とすればAの値を小数第3位まで文字列化することができます。
0そうだね
プレイ済み
返信[5]
親投稿
おちゃめ ochame_nako
ただし、プチコン3号の内部ではすべての数値は2進数で表現されています。 したがって、0.1でさえ循環小数となっているためAの値が小数第3位まであれば十分という場合であっても小数第3位までを文字列化すれば十分というわけではありません。 プチコン3号の有効桁数を考慮する必要があるためです。プチコン3号の有効桁数は52bit分あり、これは約15.6桁分の有効桁数になります。 ちなみに2進数で小数がどのように表現されるかはあらゆる数値(プチコン3号の実数型で扱うことができるすべての数値)を2進数に変換できる私の自作関数BIN64$を使いBIN64$(0.1)とすれば分かります。
1そうだね
プレイ済み
返信[6]
親投稿
おちゃめ ochame_nako
FORMAT$はどこまでの桁数を得たいのかをあらかじめ指定しておく必要があります。プチコン3号の有効桁数を考えると小数第1位までの値(0.1単位で加減算した値)を正確に文字列化するには得るためにはFORMAT$では小数17位まで指定する必要があります。 どのような数値にも対応できるようにしたいならばFORMAT$("%309.324F",A)としてプチコン3号で扱える範囲内のすべての数値を表現できる桁数を指定しておけば良いです。ただし、これを表示すれば0が羅列して非常に分かりづらいです。 表示が分かりにくければ表示の際に数値化すれば良いと考える人もいるかもしれません。 では、PRINT VAL(FORMAT$("%309.324F",A))としてみてください。 するとAがどのような値であっても「0」と表示されます。
0そうだね
プレイ済み
返信[7]
親投稿
おちゃめ ochame_nako
これはプチコン3号のVAL関数は100桁以上の文字列を数値化すると0を返す仕様になっているためです。 そのためセーブデータとして使うためには有効桁数を含めて99桁以内になるような範囲の値に限られます、 つまり、VAL関数の制限の問題が発生するため「FORMAT$を使えば万全」というわけではないということです。
0そうだね
プレイ済み
返信[8]
親投稿
おちゃめ ochame_nako
また、プチコン3号で普通に数値を表示すると指数を使って表示されないため絶対値が大きな数字は桁数が多くなって非常に分かりづらいし、絶対値の小さな数字(5e-9未満)は0と表示されてしまいます。 絶対値が大きな数字や小さな数字は指数表記の方が分かりやすいし、数値化することを考えると文字列化を行っても100桁未満にすることが求められます。 「正確さ」と「分かりやすさ」の両方の要求に応えるのがこのPSTR$なのです。 公開キー【 NKADEE93 】、ファイル名「PSTR」です。
1そうだね
プレイ済み
返信[9]
親投稿
おちゃめ ochame_nako
冒頭のサンプルの1番上の表示はA=PI()として表示の比較を行っています。 普通に表示すると小数第8位までに丸められてしまうため3.14159265となります。(小数第9位以下は普通に表示したら分からない) STR$で文字列化したものを表示すると3.14159となりますが、これをVALで数値化しても上記のように元の値には戻りません。 PSTR$では3.1415926535897931となり、これはVALで数値化した場合にはPI()の値と一致します。 3.141592653589793までが円周率の正しい値を示していてプチコン3号の実数型の有効桁数が16桁程度あることが分かると思います。(有効桁数は10進数だと16桁弱となる)
0そうだね
プレイ済み
返信[10]
親投稿
おちゃめ ochame_nako
このPSTR$は誤差ゼロで数値を文字列に変換できるためセーブデータに使えるというだけではなく様々な利用方法が考えられます。 例えば「1000」という数字が何桁の数なのかFLOOR(LOG(1000,10))+1で求められますが、なぜか「3」と表示され「1000が3桁の数」になってしまいます。 これはPSTR$を使って表示すれば3.9999999999999996となっていてこれを整数化すれば4ではなく3になるのは一目瞭然になります。 また、プチコン3号の内部では数値はすべて2進数で表現されているので「0.1」でさえも正確に表現することはできません。(0.5や0.25のような2の累乗分の1ならば正確な表現は可能) したがって、小数を含む計算をした場合には予期しない不具合が発生する場合があります。 そのような場合は普通に変数の値を表示しても発見はできませんがPSTR$を使えば発見が可能です
0そうだね
プレイ済み
返信[11]
親投稿
おちゃめ ochame_nako
例えば次のプログラムを実行して分かるように0.1を100回足しても10未満の数になり、101回目にようやく10以上の数になります。 VAR A,I WHILE A<10  INC I  A=A+0.1  ?I,A  WAIT 10 WEND
0そうだね
プレイ済み
返信[12]
親投稿
おちゃめ ochame_nako
パッと見た感じだと原因を特定するのが困難な不具合ですが、これもPSTR$を使えば理由は一目瞭然で0.1を100回足した時点では10未満の数になっているためです。 VAR A,I WHILE A<10  INC I  A=A+0.1  ?I,PSTR$(A)  WAIT 10 WEND
0そうだね
プレイ済み
返信[13]
親投稿
おちゃめ ochame_nako
「0.1を100回足したら10になるようにしたい」という場合には私の自作関数PRを使用すると良いです。(PR関数は私の過去の投稿を参照) これは数値そのものを普通に表示した時の値と同じになるように丸める関数です。 VAR A,I WHILE A<10  INC I  A=PR(A+0.1)  ?I,A  WAIT 10 WEND ?PSTR$(A) ループを抜ける時ぴったり10になっていることが分かると思います。
0そうだね
プレイ済み
返信[14]
親投稿
おちゃめ ochame_nako
また何度も書きますが内部では2進数で表現されているため10で割って10倍しても元の数に戻る保証はできません。 A=小数を含む適当な数、B=A/10*10 とした時に「A=B」になるとは限らないのでそういう時にもPSTR$を使って表示すればなぜそうなるのかが分かります。 このようにPSTR$はセーブデータ作成時に限らず値の正確な表示が必要な場面で活用することができます。
0そうだね
プレイ済み
返信[15]
親投稿
おちゃめ ochame_nako
これで、PSTR$の利便性が理解いただけたと思いますが、この大幅バージョンアップされたPSTR$は前バージョンのPSTR$から何が変わったのかを書いておきます。 (1)LOGの演算誤差によって発生していた誤動作の修正(要するにバグ修正) (2)桁揃えへの対応 (3)「-0」への対応 (4)非正規化数への対応 (5)infやnanへの対応 (1)~(5)を詳しく解説すると以下のような感じです。
0そうだね
プレイ済み
返信[16]
親投稿
おちゃめ ochame_nako
(1)プチコン3号のLOG関数は常用対数(底が10の対数)を使って計算した場合に1e3(=1000)、1e6(=1000000)みたいに10の「3の倍数乗」の時は整数値が得られるはずなのに演算誤差で小数値になってしまい正しい桁数は求めることができません。 これはすでに上記の通りでLOGを使う限りは避けられないことなのでLOGを使わずに文字列操作のみで指数表記における指数部分(常用対数による演算を整数化したもの)と同等のことを行いそれで対応しました。
0そうだね
プレイ済み
返信[17]
親投稿
おちゃめ ochame_nako
(2)STR$では桁数を指定することでセーブデータとして活用する場合には複数データを1つの文字列変数に入れる場合に便利に活用できるのですが、PSTR$にはこれに相当する機能はありませんでした。 そこで、セーブデータとして使用する場合には「SV=FALSE」の部分を「SV=TRUE」と書き換えることで文字列に変換の際は25文字固定(空いた部分には後ろにスペースを挿入)にすることでセーブデータとして活用しやすくなりました。(FALSEの時はPSTR$の最大文字数は符号込みで24文字)
0そうだね
プレイ済み
返信[18]
親投稿
へぇー。あの「e+06」には、 「×10の06乗」って意味があったんだ。 あれ?じゃあ「e-15」だと、 「×10の-15乗」って事になるのかな。 時々、作った電卓で、 そんなのが表示されちゃうので、 これを使えば良いんですね♪
0そうだね
プレイ済み
返信[19]
親投稿
おちゃめ ochame_nako
(3)プチコン3号は負数の値が関数による演算によって0に丸められた場合には符号がマイナスで仮数のビットがすべて0の「-0」という値になるのですがこれが正しく「-0」と取得できるように対応しました。 例えば、ROUND(-0.1)やSGN(-1)*0とすれば-0という値を得ることができます。-1e-9のように絶対値が5e9よりも小さい負数は普通に表示した際には「-0」になりますが、これとは異なります。
0そうだね
プレイ済み
返信[20]
親投稿
おちゃめ ochame_nako
(4)プチコン3号では2の-1022乗(2.2250738585072014e-308)が扱える正の最小値なのですが、これよりも小さくプチコン3号上では「0」として扱われる非正規化数にも対応しました。 PSTR$(5E-324)とすれば最小の正の非正規化数である4.9406564584124654e-324が取得可能です。本来ならばプチコン3号では扱えない数字であるためこの非正規化数をVALを使い数値化した際には「0」になってしまいます。
0そうだね
プレイ済み
返信[21]
親投稿
おちゃめ ochame_nako
(5)プチコン3号では2の1024乗以上の値はinf(負数の場合は-inf)になります。またinf-infやinf*0を計算するとnan(非数)になります。(-nanという値も存在する) このPSTR$では数値変数の値がinfやnanの時もinfやnanと表示が可能です。 ただし、VAL関数の仕様上A=VAL("inf")としてもAの値はinfにはならず、0になります。これを防ぐには文字列が"inf"の時にはinfという値を"nan"の時にはnanという値を返すPVAL関数などを作って対応する以外にはありません。
0そうだね
プレイ済み
返信[22]
親投稿
おちゃめ ochame_nako
(3)~(5)を有効活用できる機会はほとんどないと思いますが、その値を表示させようとしたときに表示が崩れたりエラーが発生するという問題が起きていたので対応させました。 これは最初から対応させておらず「仕様なのでバグではない」のですが、例外処理が不十分だったのも事実です。 しかし、この真PSTR$によって「普通に表示ができるのにPSTR$では表示ができない」ということがなくなりました。 長々と書きましたが、どのようなものかというのは概ね伝わったことだと思います。(分からない部分があるという人やバグを見つけたという人はコメントに書いてください)
0そうだね
プレイ済み
返信[23]
親投稿
おちゃめ ochame_nako
Newあっキーさんへ 「e」はexponent(指数)を略したものです。 ちなみにAに1億(10の8乗)を代入したい場合は、A=1E8とすればOKです。 プチコン3号の編集モードは大文字と小文字を区別しませんので「E」は大文字でも小文字でも問題ありません。
1そうだね
プレイ済み
返信[24]
親投稿
はる HARUHI-0913
その関数を二次利用していいですか?
0そうだね
プレイ済み
返信[25]
親投稿
おちゃめ ochame_nako
このPSTR$()は自由にプログラムに組み込んで使って貰って構いませんよ
0そうだね
プレイ済み
返信[26]
親投稿
はる HARUHI-0913
ありがとうございます!
0そうだね
プレイ済み