この記事の執筆者
プログラミング学習を始めて、5ヶ月ほど。Vue.js Typescript Railsを学習中の大学生.
きっかけ
Typescriptの参考書を学習中に下記のようなコードを書いたら予期しない結果になったため調べてみることにした。参考書には誤差が出る理由等は詳しく書かれていなかった。
let price = 12500
let tax = 1.1
let withTax = price * tax
console.log("金額" + price )
console.log(`税込価格は、${withTax}`)
結果
金額12500
税込価格は、13750.000000000002
上記のコードは定価である12,500円に対して税率である0.1を加えたものである。
期待していた結果としては下記のようなもの
12,500 * 1.1 = 13,750
コンピューター特有の演算誤差
このような予期しない演算結果が出るのは、どうやら調べてみるとJavascriptだけではないようだ。
コンピュータの内部では2進数で計算されているため!
らしいのだが2進数について完全に忘れていたため(おそらく高校で少しだけやった...)まずは2進数について調べてみた。
2進数
そもそも2進数とは 0と1で表された値
10進数 | 2進数 |
---|---|
0 | 0 |
1 | 1 |
3 | 11 |
4 | 100 |
5 | 101 |
6 | 110 |
7 | 111 |
0.1 | 0000 0000 . 00001 1001 1001 1001 1001... |
どうやら 0.1は2進数で表すと0000 0000 . 0001 1001 1001 1001 1001 1001 .....以下無限に続くよう(循環小数)
このように小数の一部では2進数で表すと循環小数になってしまう。よってそれを扱った演算では計算が意図しないものになることがわかった。
解決方法
let price = 12500
let tax = 1.1 * 10
let withTax = (price * tax) / 10
console.log("金額" + price )
console.log(`税込価格は、${withTax}`)
結果
金額12500
税込価格は、13750
上記のコードでは小数を10倍して整数に直す(2進数では整数の形だと循環小数にならないため)
そして、計算した結果を10で割ることによって結果を出している。
他のやり方もあるそうなのでできなかった方は以下を参考にしてください。
### まとめ
万能に見えていたコンピュータでも1と0しか把握できないことで意図しない計算結果を生む可能性があることがわかった。複雑な計算になればなるほどこのような箇所は見落としがちなので十分に注意したい。