![コンピュータの計算誤差](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_t-1024x538.png)
Excelを使った例題
ここに全国的にチェーン展開する飲食会社があるとする。
![A店、B店、C店](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_shop.jpg)
同社では利用客に5点満点のレビューをお願いしており、年度末に集計している。
昨年・今年のレビュー結果は以下の通り。
![レビュー点数表](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_ten.jpg)
さて、社長から「前年より0.1以上高かった支店には金一封を出す」とお達しがあった。
![前年よりレビュー評価が0.1以上高かった支店には金一封](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_kinippuu.jpg)
そこで経理担当者はまずExcelに昨年、今年の点数を入力。
![昨年と今年の点数](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e01.png)
次に数式を使って、0.1以上プラスの支店を抽出した。
![差が0.1以上なら〇を表示](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e02.png)
結果こうなった。
![期待通りの結果](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e03.png)
しかしこの方法には落とし穴がある。
それは小数の「計算誤差」というものを考慮していない点だ。
もしお手元にExcelがあるなら試してみて欲しい。次のようにC店の数値を書き換えると〇は消える。
![〇にならない](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e04.png)
「3.9 – 3.8」と「3.8 – 3.7」の結果はどちらも「0.1」なのに、片方には〇が付いて、もう片方には〇が付かない罠。
わかりやすくする為に、直接数字を使って計算結果を出してみた。
![計算結果はどちらも0.1](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e05.png)
表示上はどちらも「0.1」なのだが、この2つは微妙に違う。
小数点の桁数を増やせば明らかになる。
![小数点以下の表示桁数を増やす](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e06.png)
![0.1に限りなく近い数](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_e07.png)
もちろんこれはコンピュータ側の問題(というか2進数の限界)
人間が10進数で簡単にできる小数計算が、2進数で考えるコンピューターだと正確に表現できないことがあるのだ。
10進数でも「10 / 3 = 3.33333…」といった無限小数はあるが、2進数「3.8 – 3.7 = 0.09999…」もそれに近い。
機械のミスは人の責任になる
上記のように支店が3つならすぐ気づくが、100支店以上あると暗算を省略し、金一封が漏れる支店が出てくる。
そうなると誰が責任を取らされるか? 今回だとExcelを作成した経理担当者だろう。
レアケースなのでこの罠にはまる確率は低いが、仕事でExcelを使う人は一応知識として知っておこう。
正しい数式にする
計算誤差は、2進数で表現できない計算結果が、ほぼそれに近い数値で出ることが問題だ。
なので本来の桁数で四捨五入して、望みの数値に整えてしまえば良い。
![ROUND関数](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_round01.png)
今回の場合、小数点1桁同士の引き算なので、小数第2位以下が発生することはない。
「ほぼ0.1の0.09999999……」という結果は「0.1」で受け取るのが妥当だろう。
![小数点1桁でまるめ](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_round02.png)
という訳でROUND関数を使って、最初のif文を修正しよう。
丸めた計算結果と「>=0.1」の判定ならきちんと動作するはずだ。
![数式にもROUND関数を使う](https://totanrpt.com/wp-content/uploads/2022/07/it_keisangosa_round03.png)
![正しい結果](https://totanrpt.com/wp-content/uploads/2022/06/it_keisangosa_round04.png)
はっきり言って計算誤差なんてイレギュラーの範疇なので、常に意識して防止するのは困難だ。
しかし、知識があればもし遭遇しても「あれ?これってもしかして……」と気付くはずだ。
備えあれば患いなし。ぼんやりでもいいから憶えておこう。