小数の計算
まんさくさんの日記 2006/11/13:
http://www.ne.jp/asahi/new/legend/mansaku/diary.html
プログラム書いてて、double型の値2つの平均をとりたくなった時、2で割るべきだろうか?2.0で割るべきだろうか?(結果はどちらも正しい。)少し前に2.0と書かれているのを見て、自分なら2かなぁと思ったことがある。
これは僕のこと。たしか、先日のICPCのTrial Useのときだったはず。
日記に書かれていることはもっともで、意味的に2の方が気持ちが良いというのはすごく共感できます。
でも、それなのになんで自分はこう書いているんだろう、と考えてみた。すると、どうやらこれは過去の教訓からこう書くようになったっぽいと思い当たった。
つまり、こういうことを何度もやっているから。
// 点の座標をよみこむ(与えられるのは整数座標) int sx, sy, tx, ty; cin >> sx >> sy >> tx >> ty; // 中点をとる double mx, my; mx = (sx+tx)/2; my = (sy+ty)/2;
mx, myはdoubleだけど、実際には整数値に切り捨てられた値が代入される。
これを見て「そんなポカミス誰もやらねーよ!」と思った人も居ると思う。でも、この例だと単純だけど、こういった整数の割り算が複雑な式の中に出てきたりしていると気づかなかったりする。
また、それ以上に、間違って書いてしまった後にコードを読み直しても、式としては合っているので、間違いが見つけにくいというのが悪質。
そこで、いつからか分からないけど、数値型について、概ねこんな感じの規約を自分の中で作った。
- たとえ整数しか保持しない変数でも、その値から小数値が計算される場合は、最初から小数型の変数にする。(つまり、上の例ではsx,sy,tx,tyも最初からdoubleにしておく、ということ。)
- 計算の結果が小数の場合は、使う即値も小数にする。
つまり、とにかくdoubleを生むような計算には整数は現れないようにする、ということ。
一番目のルールは割と自分でも認識していて、何度か人にも言った事があるのだけど、二番目のルールはいつのまにか実行されていて、自分でも気づいてなかった。
ちなみにこのルールを盲目的に実行すると、整数格子点に点があることに依存しているとか、整数性が必要な問題を解くときに痛い目に遭ったりする。ほどほどに。