60587


「数値上ほぼ等しい場合」という条件を立てる方法を教えていただきたいです．

実数の計算を行うと，どうしても数値計算誤差が生じてしまいます．  
例えば，  
`0.027` という値が，`0.027000000000000003`という感じです．

ここで，上記の例では数値計算誤差が生じているだけで，実際は等しいはずです，  
そこで，例えば，

[code]

    a = 0.027
    b = 0.027000000000000003
    
[/code]

とするときに，

[code]

    if a == b
    
[/code]

がtrueになるようにしたいということです．

方法がわからないのでご教授いただきたいです.

（追記）

[code]

    a = 0.027
    b = 0.026000000000000002 # => b = 0.027999999999999997 でもfalse
    
[/code]

のときは，falseと判定したいです．


CC BY-SA 4.0
2019-11-16T11:51:15.130
60586
2019-11-17T08:14:19.557
30173
question
ruby
「数値上ほぼ等しい場合」という条件を立てる方法を教えてください


仮に有効数字を揃えて比較したいという場合であれば、以下の方法があるかもしれません。

[code]

    a = 0.027
    b = 0.027000000000000003
    
[/code]

[code]

    a.round(16) == b.round(16) # 丸める位は適当です。
    # => true
    
[/code]

浮動小数点演算に誤差が生じてしまうのはある程度仕方ない部分もあると思うので、それを発生させない工夫も必要かもしれません。

参考: <https://doruby.jp/users/note/entries/1>

これは手っ取り早い解決方法なので、より正確を期すなら他の方の回答も参考してみるといいと思います。（ど、どなたか…。）

（追記）

BigDecimal と Float::EPSILON を使えば、以下のようにも比較できそうです。

[code]

    (BigDecimal("1.0") - BigDecimal("1.00000000000000000000003")).abs < Float::EPSILON
    # => true
    
[/code]

Ruby のリファレンスマニュアルによると、Float::EPSILON は「1.0 + Float::EPSILON != 1.0
となる最小の正の値です。」とのことです。つまり、めちゃくちゃ小さい数ということです。  
<https://docs.ruby-lang.org/ja/2.6.0/class/Float.html#C_-E-P-S-I-L-O-N>


CC BY-SA 4.0
2019-11-16T12:29:43.573
60587
2019-11-16T13:21:56.877
2019-11-16T13:21:56.877
36656
36656
60586
answer


状況に依りますが，以下のようにBigDecimalを使い，そもそも誤差が生まれないようにするという手もあります．

[code]

    require 'bigdecimal'
    
    puts 0.1 + 0.2 == 0.3
    #=> false
    puts BigDecimal('0.1') + BigDecimal('0.2') == BigDecimal('0.3')
    #=> true
    
[/code]

これは，お金のような無限の精度を持った数を扱うような場合にはよく使われる方法です．  
BigDecimalを使うべきでない場合（科学計算等）には，以下のようにします．

[code]

    a = 0.027
    b = 0.027000000000000003
    puts (a - b).abs < 1e-10
    #=> true
    
[/code]


CC BY-SA 4.0
2019-11-16T12:55:03.893
60589
2019-11-16T14:02:39.007
2019-11-16T14:02:39.007
36544
36544
60586
answer


Epsilon を取り扱う場合、絶対値と比較するのではなく、相対誤差に変換してから計算することをお勧めします。

というのも、浮動小数点数の誤差は、絶対値ではなく、有効桁数的な、その数値のスケールに対する相対値でもって規定されるからです。

なので:

[code]

    a = 0.027
    b = 0.027000000000000003
    
    p (((a - b) / a).abs < 10 * Float::EPSILON)
    
[/code]

が個人的にはおすすめです。ここで出てきた 10
はどれぐらいの浮動小数演算による誤差を許容するかの係数で、必要に応じて調整します。一般的に、浮動小数演算を繰り返すほど、誤差は大きくなる可能性があります。


CC BY-SA 4.0
2019-11-17T08:14:19.557
60603
2019-11-17T08:14:19.557
754
60586
answer