プログラミングで少数点ありの変数比較にご用心あれ
Object-Oriented Programming (OOP) 学習を進めていて別なところにハマったのでそのメモ。「コンピューターは正確だ!😤」と思っているそこのあなたこそ必見です。
(約 2,200文字の記事です。)
double, float, decimal 打ち切り誤差の話
プログラマなら既に知っているとは思うが、プログラミング初心者にはハマりやすい罠だ。
本のサンプルコードを完成させていじっていたら、ときどき、こんな風に後ろにびろ~んと000000001が付いて表示されるときがある。いつもじゃないからタチが悪い。
// コーヒーの値段(ドル)
$1.25
$1.3900000000000001
1.25はいいのだが、なぜか1.39にはならず、1.390000000……001が付く。ちょっと前にdoubleとfloatについて調べていて知っていたのでChatGPT先生に聞いてみたらビンゴだった。
どんな言語を使っても根っこは一緒。避けられない「打ち切り誤差」
これに関する分かりやすい解説がPythonドキュメントにあったので貼っておきます。
ま、要するにどんなプログラミング言語でもdouble, floatなどの型ではどうしても打ち切り誤差があるよ、ということ。
そして「ならば何でも10進数演算のdecimal型で押し通せばいいのか?」と言われればNoで、どうやら実行速度が遅いらしい。詳細はこちら。
要するに早いdoubleまたはfloatと誤差の処理実装で運用するか、処理速度よりも精度を優先してdecimalにするかは設計次第だね。金融処理関係などはdecimal一択らしい。
UIでの表示処理なら小数点以下カット表示でOK
んで、詰まったサンプルソースコードの、次の課題があったのでそれに挑戦していた。多分できたと思ったので答え合わせしたら、そっちのコードにはキッチリ「少数点以下2桁で切って表示させる」ようにしれっと1行が変わっていた。After参照。
Before、問題の1.3900……001が出る版。しょうがないので型を全部decimalにして10進数表現にして対処してみた。それはそれでOKだ。修行である👍
Console.WriteLine(beverage.GetDescription() + " $" + beverage.Cost());
After、本の解答。そりゃ下2桁で表示を打ち止めしているわけで……。
ずるい😭
Console.WriteLine(beverage.GetDescription()
+ " $" + string.Format("{0:F2}", beverage.Cost()));
まぁ計算用ではなくてUIとしての数字表示用なのでこの打ち切り実装が一番ベストでしょうね。
ちなみにPythonでは「いい感じ」に誤差を丸め込んで表示されるファジー機能があるそうで。そういう点でもPythonは初心者向きとも言える。だが玄人にはそっちのほうが逆に分かりにくくなることもある。Pythonで学んでいてターミナルの表示結果でこういう現象に出くわさなかったことは実はPythonの内部処理のおかげだったのかもしれない。
少数点のある数字の変数の比較にご用心
小数点以下のある数値の比較には気を付けよう。
1.39と1.390000001はイコールにならない。比較結果はfalseだ。罠。
というわけで今回は「小数点以下のある変数の比較演算にご用心あれ」という結論でした😊
今日のデザインパターンの学習
Object-Oriented Programming (OOP) 学習を進めていて別なところにハマったのでそのメモ。
今日はdecoratorパターン1周目。どのパターンの章でもそうだが、1回で頭に入らない。大体3周して分かる気がする。
これまで学んだ内容
strategy pattern
observer pattern
decorator pattern ← 今ココ
ただし以前にUdemyのゾラン先生のC# のOOP教材を50時間かけて学んでいたので、その理解がこの本の理解に大いに役に立っている。
Head First本は冒頭にも書かれているように、全くのプログラミング初心者向けではない。
デコレーターパターンはどうやらこれ単体での運用よりも、次に登場するファクトリーパターンなどとの組み合わせで真価を発揮するらしい。やはりある程度のパターンを体得しないと使えないという予測は当たっているようだ。
OOPの話はこれまで。
今回の創作活動は約1時間(累積 約3,921時間)
(1,164回目のnote更新)