###小数点の演算で誤差がでてしまった
> 1 - 0.8
=> 0.19999999999999996
0.2
を期待しているのに、誤差が生じてしまってます。
1に小数点つけてもおなじ
> 1.0 - 0.8
=> 0.19999999999999996
###BigDecimalを使う方法
bigdecimalをrequireすると良い、とあったのでやってみました。
> require 'bigdecimal'
> BigDecimal("1") - BigDecimal("0.8")
=> 0.2e0
BigDecimalの引数はString型にして、誤差のない数を演算機に伝えてる(と理解した)。
理由はわからないけど答えに指数部分がついてきました。String#to_fでいい感じの小数点表示にする。
> require 'bigdecimal'
> (BigDecimal("1") - BigDecimal("0.8")).to_f
=> 0.2
####答えに整数が欲しいとき
例えば消費税計算とか。1800 * 1.08 の答えは1944が返ってきて欲しいのに、、、
> 1800 * 1.08
=> 1944.0000000000002
こういう時にBigDecimal使う。
> require 'bigdecimal'
=> true
> (BigDecimal("1800") * BigDecimal("1.08")).ceil
=> 1944
※上記に使われているFloat#ceilは「自身と等しいかより大きな整数のうち最小のものを返す」。
BigDecimal使わないとこうなる。
> (1800 * 1.08).ceil
=> 1945
###Rational(有理数)クラスを使う方法
コメントで @obelisk68 さんに教えていただきました。ありがとうございます!
そのままコピペします。
"
BigDecimal でよいのですが、Rational(有理数)クラスを使ってもよいです。ここでは0.8の浮動小数点演算が問題なので、これを有理数(分数と考えてかまいません)に直して計算します。このとき、Float#to_rではなく、Float#rationalizeを使うとよいです。
[1] pry(main)> i = 1 - 0.8.rationalize
=> (1/5)
[2] pry(main)> i.to_f
=> 0.2
あるいは0.8が決め打ちならば、有理数リテラルを使うと簡単に書けます。
[3] pry(main)> j = 1 - 8/10r
=> (1/5)
[4] pry(main)> j.to_f
=> 0.2
消費税計算もこんな感じ。
[5] pry(main)> (1800 * 108/100r).ceil
=> 1944
"
数値リテラル初めて意識しました。有理数も、、、
有理数(分数と考えてかまいません)
こういう分かりやすい説明ができる人になりたい。
浮動小数点誤差の解消法方法はいろいろあるようなので、慣れてきたら他にも調べてみたいと思います。
###参考
[Ruby]消費税計算にはBigDecimalを使いましょう
instance method String#to_f
instance method Float#ceil
class Rational