web-dev-qa-db-ja.com

等しい、より大きい、より小さい、より小さい、等しい、以上の場合のDouble.Epsilon

http://msdn.Microsoft.com/en-us/library/system.double.epsilon.aspx

2つの浮動小数点数を等しいと見なすことができるかどうかを決定するカスタムアルゴリズムを作成する場合、イプシロン定数より大きい値を使用して、2つの値が等しいと見なされる許容差の絶対マージンを確立する必要があります。 (通常、その差のマージンはEpsilonよりも何倍も大きいです。)

これは実際に比較に使用できるイプシロンではないのですか? MSDNの言葉遣いを本当に理解していません。

ここの例でイプシロンとして使用できますか? - floatとdoubleの比較で最も効果的な方法は何ですか?

そして最後に、これは本当に重要だと思うので、平等、以上、以下、以下、または以上の確実な実装を確実にしたいと思います。

52
ss2k

私は知らないwhat彼らがそれを書いたときに彼らは喫煙していた。 Double.Epsilonは、0ではない、表現可能な最小の非正規浮動小数点値です。切り捨てエラーがある場合、この値よりも常に大きいになることを知っているだけです。はるかに大きいです。

System.Doubleタイプは、最大15桁の正確な値を表すことができます。したがって、double値xが何らかの定数に等しい場合の単純な1次推定は、定数* 1E-15のイプシロンを使用することです

public static bool AboutEqual(double x, double y) {
    double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15;
    return Math.Abs(x - y) <= epsilon;
}

ただし、切り捨てエラーが蓄積する可能性があるので注意が必要です。 xyの両方が計算値である場合、イプシロンを増やす必要があります。

76
Hans Passant

同等、以上、以下、以下、および以上の確実な実装を確実にしたいと思います。

バイナリ浮動小数点演算を使用しています。

バイナリ浮動小数点演算は、長さ、質量、電荷、時間などの物理量を表すように設計されました。

おそらく、使用することを目的としてバイナリ浮動小数点演算を使用していると思われます。物理量の演算を行うためです。

物理量の測定には、測定に使用するデバイスの精度に応じて、常に特定の精度があります。

あなたが操作している量の値を提供しているので、あなたはその量の「エラーバー」が何であるかを知っている人です。たとえば、「建物の高さは123.56メートル」という数量を指定している場合、これはセンチメートルでは正確ですが、マイクロメートルでは正確ではないことがわかります。

したがって、2つの量が等しいかどうかを比較する場合、望ましいセマンティクスは、「これらの2つの量は、各測定で指定されたエラーバー内で等しいか」ということです。

それで、あなたの質問に対する答えがあります。あなたがしなければならないのは、各数量のエラーを追跡することです。たとえば、建物の高さは「123.56メートルの0.01以内」です。これは、測定がどれほど正確かを知っているからです。次に、123.5587という別の測定値を取得し、2つの測定値が許容誤差内で「等しい」かどうかを知りたい場合は、減算を実行して、許容誤差に収まるかどうかを確認します。この場合はそうです。測定値が実際にマイクロメートルに対して正確だった場合、それらは等しくありません。

要するに、あなたがここで操作できる数値がそもそもどこから来たのかを知っているのはあなただけだからです。測定に使用した機器の精度を考慮して、測定に意味のある許容誤差を使用してください。

45
Eric Lippert

1.0に近い2つのdouble値があり、それらの最下位ビットのみが異なる場合、それらの差はDouble.Epsilonよりも桁違いに大きくなります。実際、この差は324桁です。これは、指数部の効果によるものです。 Double.Epsilonには巨大な負の指数があり、1.0の指数はゼロです(もちろん、バイアスが除去された後)。

2つの類似した値を比較して同等にする場合は、比較する値の大きさのオーダーに適したカスタムイプシロン値を選択する必要があります。

比較するdouble値が1.0に近い場合。その場合、最下位ビットの値は0.0000000000000001に近くなります。比較しているdouble値が四角である場合、最下位ビットの値は1000に達する可能性があります。これらの両方の状況で、イプシロンの単一の値を使用して等値比較を行うことはできません。

9

ケントボガーツのアイデアを使用して、これを実行しました。

private bool IsApproximatelyEqual(double x, double y, double acceptableVariance)
{
     double variance = x > y ? x - y : y - x;
     return variance < acceptableVariance;

     //or
     //return Math.Abs(x - y) < acceptableVariance;
}
6
Matt Canty

2つの値が正確に等しいか、double型で表現可能な最小の差があることを確認したい場合、比較に使用できます。一般的に、2つのdoubleがほぼ等しいかどうかを確認するには、double.Epsilonより大きい数を使用します。

.NETフレームワークが次のようなものを定義しない理由

bool IsApproximatelyEqual(double value, double permittedVariance);

私を超えています。

4
Kent Boogaart

私は次を使用します

public static class MathUtil {
    /// <summary>
    /// smallest such that 1.0+EpsilonF != 1.0
    /// </summary>
    public const float EpsilonF = 1.192092896e-07F;

    /// <summary>
    /// smallest such that 1.0+EpsilonD != 1.0
    /// </summary>
    public const double EpsilonD = 2.2204460492503131e-016;

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static bool IsZero( this double value ) {
        return value < EpsilonD && value > -EpsilonD;
    }

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static int Sign( this double value ) {
        if ( value < -EpsilonD ) {
            return -1;
        }
        if ( value > EpsilonD )
            return 1;
        return 0;
    }

そして、2つのダブル「a」と「b」の等価性をチェックしたい場合は、使用することができます

(a-b).IsZero();

比較結果を取得したい場合は、

(a-b).Sign();
3
Panos Theof

投稿したMSDNリンクの適切な部分は次のとおりです。

ただし、Epsilonプロパティは、Double型の精度の一般的な尺度ではありません。値がゼロのDoubleインスタンスにのみ適用されます。

注:Epsilonプロパティの値は、マシンイプシロンとは異なります。マシンイプシロンは、浮動小数点演算の丸めによる相対誤差の上限を表します。

この値は、x + 1.0が1.0に等しくないように、最小の正数xとして定義されていないため、Double.Epsilonを「ほぼ等しい」に使用することはできません。 x + 1.0が1.0に等しくないように、値が最小の正の数xである定数がフレームワークに存在しません。

私は言わなければならない、それは私を驚かせる。私も、Double.Epsilonはc/c ++のDBL_EPSILONと同等であると想定していました。明らかに違います!

そのリンクについて私が読むことができることから、控えめに言ってもかなり驚くべきことですが、「比較のために自分でまともな値を把握する必要がある」と言っているようです。
おそらく、もっと知識のある人が明らかにできるでしょう:)

3
zebrabox

Doubleの比較に関する問題は、等しいが、丸め誤差のために同じ値に評価されない2つの異なる数学結果を比較すると、何らかの違いが生じることです...これはイプシロンより大きい、エッジの場合を除く。また、信頼できるイプシロン値を使用することも困難です。静的最小差イプシロンを使用すると、ダブル自体が高低の場合に差が小さすぎたり大きすぎたりする可能性があるため、2つのダブルの差がパーセンテージ値より小さい場合、2つのダブルを等しいと考える人もいます。

1
Brian

自分で計算するか、独自の定数を定義する必要はありません。

double calculateMachineEpsilon() {
    double result = 1.0;
    double one = 1.0/256;

    while(one + result/2.0 != 1.0) {
        result/=2.0;
    }
    return result;
}
0
Marek R

以下は、Silverlight Control Toolkit内に2回含まれているコードです。

    public static bool AreClose(double value1, double value2)
    {
        //in case they are Infinities (then epsilon check does not work)
        if(value1 == value2) return true;
        // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
        double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
        double delta = value1 - value2;
        return(-eps < delta) && (eps > delta);
    }

ある場所では、1e-6イプシロン;別の場合は、1.192093E-07。独自のイプシロンを選択する必要があります。

0
Gabe