2017-10-15 3 views
0

等しくない:私のプログラムによって作成された値が、残念ながら最初の1である私の場合は2つの非常に近い浮動小数点数は、IRBで

0.9999999999999998 
# => 0.9999999999999998 
0.99999999999999998 
# => 1.0 

0.9999999999999998 == 1.0 
# => false 
0.99999999999999998 == 1.0 
# => true 

もちょうどinspect値を示します、私は値が1に等しいことを検証するテストケースを書くのに問題があります。

私は、次のオプションの間で決定しています:

  1. は、アプリケーションコードでround呼び出しを追加、しかし、アプリケーションが既に働いている、私はちょうど
  2. は、テストコード
  3. roundの呼び出しを追加し、テストすることができません
  4. ???

お勧めのアプローチは何ですか? 10進数の後に15を0にして1.0を扱うようにプログラムを構成する方法はありますか?小数点以下16桁が切り捨てられているように思えるので、ちょっとイライラします。小さな浮動小数点の違いを比較する方法については、この記事読ん

+1

IRBは、任意の精度を持つBigDecimal型ではなく、固定精度を持つFloat型として10進浮動小数点値を解釈していることがわかりました。それはあなたのプログラムが何をすべきか、あるいは何をすべきか、あるいはあなたのテストが何をするべきか、何をすべきかについてほとんど言及していません。 –

+1

浮動小数点数の等価比較を厳密に(in)実行することはめったに適切ではないことにも注意してください。任意精度の数値を使用しても、それは実際には変更されません。特定のアドバイスが必要な場合は、テストする述部が何であるかを明確にする必要があります。 –

+0

@JohnBollinger私は '0.9999999999999998 == 1.0'のような方法でフロートを設定する方法があるのだろうかと思います。私が言ったように、この値(15ナインズ)は、必要とする精度(16ナイン)から1つだけ離れているようです。私は[Float](https://ruby-doc.org/core-2.2.3/Float.html)クラスの定数を見始めました。私は 'EPSILON'と' DIG'を変更しようとしましたが、効果がありません。 –

答えて

3


http://c-faq.com/fp/fpequal.html

は、私は、Rubyへのソリューション提案換算:

class Float 
    MY_EPSILON = 0.000000000000001 
    MY_TOLERANCE = 0.000000000000001 

    def eq_epsilon?(flt) 
    a = self 
    b = flt 

    (a - b).abs <= MY_EPSILON * a.abs 
    end 

    def self.reldif(a, b) 
    c = a.abs 
    d = b.abs 
    d = [c,d].max 

    d == 0.0 ? 0.0 : (a - b).abs/d 
    end 

    def eq_reldif?(flt) 
    Float.reldif(self, flt) <= MY_TOLERANCE 
    end 
end 

をこうして我々はいくつかのテストコードを実行することができます:

f1 = 0.99999999999999998 
f2 = 0.9999999999999998 
f3 = 0.999999999999998 

[f1, f2, f3].each { |f| 
    p f.eq_epsilon?(1.0) 
    p 1.0.eq_epsilon?(f) 
} 

puts "--------------" 

[f1, f2, f3].each { |f| 
    p f.eq_reldif?(1.0) 
    p 1.0.eq_reldif?(f) 
} 

出力あり:

true 
true 
true 
true 
false 
false 
-------------- 
true 
true 
true 
true 
false 
false 

ただし、すべての要件を満たしているかどうかを確認するには、おそらくさらにテストが必要です。

関連する問題