コミュニティアイコン プチコン 非公式コミュニティ トピック

アバター
りょくちゃくん ◆/cOfIDJioXYN
2018/12/11 22:05
質問
同じ数のはずなのに…?
ループ内で変数Mに0.05を足し続け、?Mと?FLOOR(M)を実行するプログラムを組んだのですが…変数Mは4と表示させているのに、FLOOR(M)は3と表示されてしまいます。
こういった現象はなぜ起きてしまうのでしょうか。また、内部では変数Mはどういった数が代入されているのでしょうか。できればこういった現象の対策(変数MとFLOOR(M)が常に同じ値になるようにしたい)があれば教えていただけると助かります。

コメント

アバター
takumi 2018/12/11 22:29 ◆Ce3Q40uXWJjn
1や2の時はFLOORも同じ値ですね・・・
他の0.02や0.5をしてみると正常なことから、バグ(?)かと。
アバター
シロ 2018/12/11 22:51 ◆g0oUAxBiWqcj
バグと言われると微妙だが、これは治せない現象だと思います。? 3.99999999とすると4が表示される様に4に達していない数がMに入っています、またなぜ4に達しないかを簡単に言うと機械で小数点があるもので算出すると誤差が出てしまうためです。基本的な解決方法は正確な値を算出したいなら小数点を使わないことをお勧めします。例えば今回のケースでは0.05でなく5にして使用するときでけ100で割ると良いです。
アバター
takumi 2018/12/11 23:05 ◆Ce3Q40uXWJjn
なるほど。
確かに計算プログラムで小数点に弱いって書いてあるのはこういうことか。
感心感心。
アバター
りょくちゃくん 2018/12/11 23:10 ◆/cOfIDJioXYN
やはり仕様のようなものなのですね…また解決策もそういった方法は全く思いつきませんでした。ご指南いただきありがとうございました。
アバター
おちゃめ 2018/12/12 3:13 ◆jH1opV6FnGyx
これはプチコン3号の実数型(浮動小数点型)の仕様です。
基本的に2の累乗で表現できない小数にはすべて誤差が出るため単純に加算するだけでも誤差がどんどん蓄積されていきます。

その仕組みや対処方法については私のサイトのプチコン3号講座でまとめているのでぜひ参考にしてみてください。
http://ochameclub.web.fc2.com/petitcom3/lecture/floating_point_error.htm
アバター
りょくちゃくん 2018/12/12 3:20 ◆/cOfIDJioXYN
やはり以前どっかで聞いた浮動小数点という仕組みを使っているようですね。時間のあるときにじっくり読ませていただきます。ありがとうございます。
アバター
こういち 2018/12/12 11:34 ◆ou0jbJnEJ0Kb
人間の感覚で言うと
0.333333…+0.333333…+0.3333333…
が1じゃなくて0.999999…になるようなイメージ。
アバター
だにえる 2018/12/12 11:48 ◆m76OCAQyrWGt
1/3 + 1/3 + 1/3 = 1 = 0.99999......


0.0625とか2進数で表し切れる値だと
こういったバグは出にくくなる。
アバター
おちゃめ 2018/12/12 12:38 ◆jH1opV6FnGyx
私のプチコン3号講座でも書いていますが、この実数型の誤差はたとえるならば0.3333+0.3333+0.3333を0.9999としてしまうために発生してしまう誤差です。
もしも、プチコン3号が無限の桁数を記録できならば誤差は発生しませんが、2進数で最大52桁の計算しかできないために計算すればするほど誤差が蓄積されていくわけです。

とはいえ、プチコン3号の実数型も10進数換算で16桁弱の演算精度があるため普通に電卓代わりとして使うならば困ることはほとんどないでしょう。
この誤差はプチコン3号で変数の値を表示しても分かりません。(表示の際に小数第9位が四捨五入されるため)
したがって、どの程度の誤差があるのかを知りたければFORMAT$か自作関数PSTR$を使用する必要があります。

この誤差による誤動作防止策としては誤差を許容する記述を行うのが一般的なのですが、表示をイメージ通りに行いたいのであれば自作関数PRを使うのがもっとも簡単です。
これは見た目通りの値に丸める関数なので誤差を無視してくれます。

詳しくはプチコン3号講座に書いています。
アバター
シロ 2018/12/12 13:10 ◆g0oUAxBiWqcj
誤差を許容するで思い出したが、実数を条件文で使う場合は『一致』と『以上』『以下』は使ってはいけない、『より大きい』か『より小さい』を使うべきって習ったな。
アバター
はやピー 2018/12/12 16:09 ◆WUk.BW.kE3Qp
なるほど
アバター
りょくちゃくん 2018/12/12 18:25 ◆/cOfIDJioXYN
わかりやすく&詳しく解説していただき誠に恐縮でございます。コンピュータというものは自分の思いもよらないところで思いもよらないことが起きているようですね…(?)
整数を使用するなどし私なりに対策していこうと思います。
アバター
たんじぇ 2018/12/13 11:51 ◆WDmFkVwZ4yMl
小数点以下の値を使うプログラムはプチコン以外でも同じ問題があるので、小数点以下を扱う場合は必ず誤差が発生すると思っておいたほうがよいです。

どうしても小数点以下をちゃんと計算したい場合、シロさんの書いているように小数点以下2桁を使うなら100倍した値で計算しておいて、使うときだけ100で割るというようなやりかたがあります。

このやりかたは実際に VisualBasicの Currency型(通貨型) の内部で使われています。
※通貨だと1円とか1ドル単位で扱うけど1銭や1セントや消費税計算は小数点以下で扱います
※ついでにお金の計算の場合は小数点以下を無限につかうのではなくある程度で切り上げや切り捨てがお金の計算の仕様になるのがほとんどなので問題ないのです。


小数点以下の数値を加算し続ける場合、加算する値を小数点以下で持つのでは無く、整数値と分数の分子と分母を持つというやり方もあります。
0.05は 1/20 なので 1と20をもっておいて、1を加算していって20を超えたら正数部分を+1するというやりかたです。
変数のもちかたとか加算や計算がDEFを用意したりしないとめんどうになるけど、割り切れないような値のBPMを元にビートごとで処理をするみたいなのを誤差の蓄積が無く処理することができます。
※BPMを元にして1フレームごとに処理するには1フレームにどのぐらい値を加算して何の値を超えたかを判定するのにいろいろ計算しないとだったりします
アバター
りょくちゃくん 2018/12/13 17:03 ◆/cOfIDJioXYN
私が今しようとしていることもBPMを使ったものなのですが思った以上に難しくややこしい処理が必要なようですね…ただ実現したい気持ちが強いのでいただいたアドバイスをもとに頑張ってみます。

コメントを書く

  • こちらは「プチコン3号」「プチコンBIG」など、プチコンシリーズに関する話題を扱ったコミュニティです
  • プチコンシリーズにまったく関係ない書き込みはご遠慮下さい。削除の対象となります
  • こちらにはその他のゲームや雑談のコミュニティはなく、作る予定もありません (ひとりで管理できないため)。ごめんなさい
  • ユーザー登録なしで書き込みができます
  • 秘密の合い言葉は成りすましの防止 (トリップ機能)、書き込みの編集時の本人認証に使用します
  • 秘密の合い言葉に他人に推測されやすい言葉、他サービスと同じパスワードは入力しないでください。
  • 書き込むと、投稿時に入力したお名前と秘密の暗号が記憶され、ログイン状態になります

- WEB PATIO -