【COBOL 読み2-9-2】小数点での比較の危険性〜愛かドケチか

🧩今日の学び
・小数は2進数では正確に表せず、比較やループ条件でズレが生じる
・「ピッタリ一致」を信じないのがCOBOL流の安全設計思想
・小数を扱う処理は、整数スケールに変換して制御するのが現場の基本

なるお)係長ー、昨日ちょっと調べてたら、

「小数ループは使い方に注意」
「精度誤差が発生するからきちんと考えておくのが大事」

みたいなのが出てきたんですけど、わかります?

係長)お前でも調べることがあるんだな。どれ、どんなサイトみてんだ?

目次

小数ループがズレる理由:0.1は“正確な数”じゃない

な)いやー、なんか「0.1ずつ増やすとズレる」とか書いてて、まさかCOBOLが“ズレる系男子”だったとは。

黒縁メガネにぴっちり七三分けが作ったんだから、ビシッとしててほしいですよねー。

係)黒縁七三分け関係あるのかそれ…

まぁ…小数ループは、浮動小数点の丸め誤差ってやつが原因で“正確に止まらない”ことがあるんだ。

       MOVE 0 TO X
       PERFORM VARYING X FROM 0 BY 0.1 UNTIL X > 1
           DISPLAY "X = " X
       END-PERFORM

見た目は「0.1ずつ増やして1まで」なんだけど、実際は内部で 0.9999999… みたいな数になって、UNTIL X > 1 の判定がズレることがある。

その結果

・1回多くループする

・逆に1回足りない

ってことが起こり得る。

な)うわ、それ地味に怖いやつ!
係長の顔より怖いっすよ!いや同じぐらいですかね?いや係長のほうが確実に怖かったですね。すんません。

係)なんの謝罪だよ!怖いのは“顔”じゃなく“精度”だ!

だから、実務ではこうする。

対策(整数ベース)

対策① 小数を整数に変換してループ

例えば、0.1刻みを扱いたいなら、整数で10倍して回す。

PERFORM VARYING I FROM 0 BY 1 UNTIL I > 10
    COMPUTE X = I / 10
    DISPLAY "X = " X
END-PERFORM

ループ変数「I」は、整数(0〜10)で動く。

計算結果を出すときだけ / 10 で小数化する。

→ こうすれば内部的には誤差ゼロ。

「10回ループ」「0.1刻み」という意図も正確に保てるだろ?

な)ふむふむ

対策② 比較は「=」ではなく「>=」で終わらせる

係)誤差でピッタリ一致しないことを想定して、少し“余裕”を持たせる。

つまり“ピッタリ比較しない”ってこと。

な)え、ピッタリ比較しちゃダメなんすか!?

係)ダメだ。
たとえば UNTIL X = 1.0 って書いたら、中身が0.9999999999だったら“まだ1じゃない”って思われてループが止まらん。

だから、こうする。

       PERFORM UNTIL X >= 1.0

な)そもそもなんでぴったりじゃないんでしたっけ…?

なにをどう間違えたら0.9999999になるんすか。
前世の俺でも1じゃないの丸わかりですよ!

係)前世のお前も大したことはないってことだな。

コンピュータは「2進数(binary)」で計算してるからだ。

な)ほえ?

ピッタリ比較が地雷な理由:2進数の世界では割り切れない

係)人間が使う「10進数」だと

0.1 = 1/10

できっちり表せる。

でもコンピュータは「2進数」だから、

0.1(10進) = 0.00011001100110011...(2進)

とかになる。

な)え、つまり「2進数で0.1を正確に表せない」ってこと?

係)その通り。

仕方ないから、コンピュータは途中で切り捨てて「だいたい0.1っぽい数字」で代用してる。

それが「浮動小数点(floating point)」だ。

な)うわ、それ“だいたい”とか言ってる時点で信用できないやつじゃないすか。

「ちょっ、あと5000円入れたら確変入るから金貸してくれ!すぐ返すから!ダイジョーブだって!」とか8万使ってるやつのセリフじゃないっすよね!

係)お前どんなやつと遊びにいってんだ…

でも、COBOL界でそれ言ったら即クビだぞ。

な)え!?

係)たとえば

0.1 + 0.2

って本来は0.3だけど、内部的には

0.1000000001 + 0.2000000002 = 0.3000000003

とかになって、結果を四捨五入して表示してるだけ。

な)だから見た目は「0.3」に見えるけど、実際は「限りなく近いけど違う」んですね。

係)そう。

だから「ピッタリ比較(=)」が危険。

おむすび

な)ふむむー宝くじあたったー100億のロトだったーすぐ仕事やめて、換金しに番号123456789の宝くじ持っていったら、それ番号が12345688.99だから無効ですーと言われて、無職誕生無職転生無職万歳ってやつですね。

係長は換金するまでは信じないと…

係)そうだ。

な)てか、係長は換金してもまだ信じないタイプじゃないっすか?

逮捕されるとか言って、いつまでも金使わないタイプじゃないっすか?

もう逮捕前にさっさと俺にくださいよ!

係)お前にやる金は1埃(あい)もない。って、逮捕前提に話すんな!

いいか、

  • 10進小数は、2進では“割り切れない”
  • だから誤差が出る
  • だから整数スケールで制御するのが現場流儀

な)なるほど……
つまり、浮動小数点は“見た目はキレイでも中身はズレてる”ってことっすね。

ところで「1あい」ってなんです?

係)調べとけ。

な)はい…?

1あい1あいっと…10の-10乗…?

つまり0.0000000001円…? ドケチ!?

係長のワンポイント

0.1 はコンピュータにとって「正確に表せない数」だ。
だから小数でループや比較をすると、止まるはずの場所で止まらない。
実務では 整数にスケールして回す のが鉄板の安全策になる。
どうしても小数を使うなら、比較は「=」ではなく「>=」で逃げ道を作れ。
見た目を信じるな、中身を疑え──それが浮動小数点と付き合う作法だ。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次