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

コメント