2013-07-01 4 views
11

浮動小数点数をa_float == b_floatと比較すると、a_float/3.0 * 3.0は丸め誤差のためa_floatと等しくない可能性があります。浮動小数点の等価と公差

通常どんなものがfabs(a_float - b_float) < tolのようなものです。

どのように計算しますかtol

許容誤差は、最小有効数字の1つまたは2つの値よりも大きければ理想的です。したがって、単精度浮動小数点数がtol = 10E-6の場合は、ほぼ正しいはずです。しかし、これは、a_floatが非常に小さいか、または非常に大きくなる可能性がある一般的なケースではうまく機能しません。

一般的なケースで正しくtolを計算するにはどうすればよいですか?私はCまたはC++の場合に特に興味があります。

+1

:代わりに、一定の許容範囲の

、あなたはおそらくのようにイプシロンの要因を使用することができますか? – NINCOMPOOP

+0

完全精度を求めている場合は、有理数ライブラリの1つを使用できます。 –

+3

Q:すべての一般的なケースに対して 'tol'を正しく計算するにはどうすればよいですか? A:そうではありません。許容値にかかわらず、この種の比較はすべての場合に適していません(そしてFWIWは、あなたがテストしているものに対して適切な許容値が*何かを最もよく知っているでしょうか?) –

答えて

15

このブログ投稿では、それはまた、シリーズの一つであるので、あなたはいつもより多くを読むことができます http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ その背後たとえば、かなり確実な実施、詳細な理論が含まれています。 要約:ほとんどの数字にはULPを使用し、ゼロに近い数字にはイプシロンを使用しますが、注意点はあります。あなたが浮動小数点数学について確かめたいなら、私はシリーズ全体を読むことをお勧めします。

+0

downvoteの理由は? – aryjczyk

+0

これは良い記事です - ダウンボートに同意しないでください。 – chux

+2

正確な浮動小数点の比較は通常は*問題を探していますが、常にそうであるとは限りません。私がここに書類を書いているように、正確な比較よりも些細なものが賢明でない場合があります。 https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ すべては文脈によって異なります。つまり、 'tol'の正しい値がゼロになることがあります。 –

9

私が知る限り、1つはありません。

一般的な「正解」はありません。アプリケーションの精度要件に依存する可能性があるためです。

たとえば、画面ピクセルで作業する2D物理シミュレーションでは、ピクセルの1/4が十分であると判断され、原子炉プラントの内部設計に使用される3D CADシステムではそうではないと判断される場合があります。

これをプログラムで外部から判断する方法はありません。

+0

私は合理的に可能な限り高い精度を求めています。これは、丸め誤差を許容するために、記憶域タイプの有効数字の1から2を引いたものです。 – doron

+0

浮動小数点エラーは、実行された正確な操作がわからない場合に限定されません。 'a == 3e10000'があり、' 1'を100000時間引き算すると、 'a == 2 ...'を得ることができません。 – urzeit

+2

@urzeit浮動小数点エラーにかかわらず、 '3e10000 - 100000'は' 2'ではないと確信しています。 –

-2

私は山車を比較する必要があるとき、私はこの

bool same(double a, double b, double error) { 
    double x; 
    if(a == 0) { 
     x = b; 
    } else if(b == 0) { 
     x = a; 
    } else { 
     x = (a-b)/a; 
    } 
    return fabs(x) < error; 
} 
3

のようなコードを使用するには、トラップ、スネアや抜け穴の世界へようこそ。他のところで述べたように、浮動小数点の等価性と公差の汎用ソリューションはではなく、が存在します。それを考えると、プログラマが選択した場合に使用できるツールと公理があります。

fabs(a_float - b_float) < tolには、次のような欠点があります。「a_floatが非常に小さいか、または非常に大きい可能性がある一般的なケースではうまく機能しません。 fabs(a_float - ref_float) <= fabs(ref_float * tol)はバリアントの範囲にはるかに優れています。

OPの「浮動小数点数単精度を使用TOL = 10E-6は」CおよびC++のためのビット気になることがようになるので、容易doublefloat算術を促進し、それはdoubleの「寛容」だないfloat遊びます。 float f = 1.0; printf("%.20f\n", f/7.0);を考えてください多くの新しいプログラマーは7.0doubleの精度計算を引き起こしたことを認識しません。大量のデータがより小さいサイズのfloatを必要とする場合を除き、doubleを使用することをお勧めします。

C99には、「許容値」の測定に役立つnextafter()があります。それを使用して、次の表現可能な数を決定することができます。これはOPの助けになる "...丸め誤差を可能にするストレージタイプマイナス1のための有効桁の完全数...。」if ((nextafter(x, -INF) <= y && (y <= nextafter(x, +INF))) ...

tolの種類または 『使用公差は、』多くの場合、問題の核心である。ほとんどの場合、(私見)相対公差は重要である。例えば?たまに絶対許容度が必要とされている「0.0001%以内xとyのです」。例えば「0.0001内でのxとyは」?

寛容の多くの場合、状況に応じて最適な値が決定されるため、議論の余地があります。ドルではなく、円ではない。 (ヒント:簡単な更新を可能にするコーディングスタイルを使用してください)

5

Cヘッダファイル<float.h>は1.0と1.0より大きい最小の数との差が、フロート/ということである、あなたの定数FLT_EPSILONDBL_EPSILONを与えます二重表現することができます。あなたが容認したいあなたの数字の大きさと丸め誤差によりこれを拡張することができます

#include <float.h> 
#ifndef DBL_TRUE_MIN 
/* DBL_TRUE_MIN is a common non-standard extension for the minimum denorm value 
* DBL_MIN is the minimum non-denorm value -- use that if TRUE_MIN is not defined */ 
#define DBL_TRUE_MIN DBL_MIN 
#endif 

/* return the difference between |x| and the next larger representable double */ 
double dbl_epsilon(double x) { 
    int exp; 
    if (frexp(x, &exp) == 0.0) 
     return DBL_TRUE_MIN; 
    return ldexp(DBL_EPSILON, exp-1); 
} 
+0

このテクニックは実用的ですが、ゼロ付近の数字では失敗します。相対誤差はゼロで無意味であるため、これは基本的な問題です。たとえば、sin(M_PI)は 'should'がゼロである必要がありますが、そうではありません。相対誤差は無限大です。詳細についてはこちらの記事を参照してください。 http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ –

0

許容範囲の値は、状況によって異なりますが、あなたが精密comparasionを探しているなら、あなたは許容範囲として使用することができマシンイプシロン値、numeric_limits ::εilon()(ライブラリの制限)。この関数は、1とデータ型で表現可能な1より大きい最小値の差を返します。 http://msdn.microsoft.com/en-us/library/6x7575x3.aspx

浮動小数点数または2倍数を比較する場合、εの値は異なります。たとえば、私のコンピュータでは、浮動小数点を比較するとεの値は1.1920929e-007であり、二倍を比較するとεの値は2.2204460492503131e-016となります。

xとyの相対比較のために、xとyの最大絶対値でεを掛けます。

上記の結果には、精度で再生できるulps(最後の単位)が乗算されます。

#include <iostream> 
#include <cmath> 
#include <limits> 

template<class T> bool are_almost_equal(T x, T y, int ulp) 
{ 
    if(std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::max(std::abs(x), std::abs(y)) * ulp){ 
     return true; 
    }else{ 
     return false; 
    }   
} 
+0

これは以前の回答の複製です。 –

+0

私は少しの情報とコードを加えました@BruceDawson – MartaF

+0

'if(cond)return true;を書く必要はありません。そうでなければfalseを返します。なぜあなたは 'return cond'を書かないのですか? – 0xbadf00d

1

丸め誤差は、操作に使用される値によって異なります。あなたは[この](http://en.wikibooks.org/wiki/Floating_Point/Epsilon)を読みました

bool nearly_equal(double a, double b, int factor /* a factor of epsilon */) 
{ 
    double min_a = a - (a - std::nextafter(a, std::numeric_limits<double>::lowest())) * factor; 
    double max_a = a + (std::nextafter(a, std::numeric_limits<double>::max()) - a) * factor; 

    return min_a <= b && max_a >= b; 
} 
+0

私は、コンセプトの一般化は、「ほぼ等しい」が主観的であると考えます。他のオペレータ/操作に関してはほぼ同じです。結局のところ、イプシロンは近接、逆距離で分類するために使用され、「距離」のメトリックと「逆」を導出/定義する操作を定義する必要があります。イプシロンが「手を振っている」ならば、参照の枠を持たないイプシロンは完全にジェダイのトリッキーです。 –

関連する問題