Double.Epsilon表示相等,大于,小于,小于或等于,大于或等于

时间:2010-03-09 18:11:05

标签: c# epsilon

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

  

如果您创建自定义算法   确定是否有两个浮点   你可以认为数字是平等的   必须使用大于的值   Epsilon不断建立起来   可接受的绝对边际   这两个值的差异   被认为是平等(通常,那   差异很大一倍   大于Epsilon。)

这不是真的可以用于比较的epsilon吗?我真的不明白MSDN的措辞。

这里的例子中可以用作epsilon吗? - What is the most effective way for float and double comparison?

最后这看起来非常重要,所以我想确保我有一个可靠的实现平等,大于,小于,小于或等于,大于或等于。

10 个答案:

答案 0 :(得分:74)

我不知道他们写的时候吸烟了什么Double.Epsilon是最小的可表示非非正规浮点值,不是0.你所知道的是,如果存在截断错误,它将始终大于。更大。

System.Double类型可以表示最多15位数的值。因此,如果双值x等于某个常数,则简单的一阶估计是使用常数* 1E-15的epsilon

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都是计算值,则必须增加epsilon。

答案 1 :(得分:45)

  

我想确保我有一个可靠的实现,包括大于,小于,小于或等于,大于或等于。

您正在使用二进制浮点运算。

二进制浮点运算用于表示物理量,如长度,质量,电荷,时间等。

据推测,您正在使用二进制浮点运算,因为它是用于对物理量进行算术运算。

物理量的测量始终具有特定的精度,具体取决于用于测量它们的设备的精度。

由于您是为您操纵的数量提供值的人,因此您就知道该数量上的“误差条”是什么。例如,如果您提供的数量“建筑物的高度为123.56米”,那么您知道这精确到厘米,而不是微米。

因此,当比较两个相等的数量时,所需的语义是“这两个数量是否在每个测量指定的误差条内相等?”

现在我们已经回答了你的问题。你必须做的是跟踪每个数量的错误;例如,建筑物的高度“在123.56米的0.01之内”,因为您知道测量的精确度。如果您再获得另一个测量值123.5587并想知道两个测量值是否在误差容差范围内“相等”,则进行减法并查看它是否属于误差容限。在这种情况下确实如此。如果测量结果实际上对于微米是精确的,则它们不相等。

简而言之:你是这里唯一知道什么是明智的错误容忍度的人,因为你是唯一一个知道你操纵的数字来自哪里的人。根据您用于生产设备的精度,使用对测量有意义的任何误差容差。

答案 2 :(得分:9)

如果你有两个接近1.0的双精度值,但它们的最低有效位不同,那么它们之间的差异将比Double.Epsilon大许多个数量级。实际上,差异是324个十进制数量级。这是因为指数部分的影响。 Double.Epsilon上有一个巨大的负指数,而1.0的指数为零(当然,除去偏差之后)。

如果要比较两个相似的值是否相等,则需要选择适合要比较的值的数量级大小的自定义epsilon值。

如果您要比较的双精度值接近1.0。那么最小重要位的值将接近0.0000000000000001。如果您要比较的双精度值在四元组中,那么最低有效位的值可能高达一千。在这两种情况下,epsilon的单个值都不能用于相等比较。

答案 3 :(得分:6)

我刚刚这样做 - 使用Kent Bogarts的想法。

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;
}

答案 4 :(得分:4)

它可以用于比较,假设您要确保两个值完全相等,或者具有double类型的最小可表示差异。一般来说,您希望使用大于double.Epsilon的数字来检查两个双打是否大致相等。

为什么.NET框架没有定义类似

的内容
bool IsApproximatelyEqual(double value, double permittedVariance);

超出我的范围。

答案 5 :(得分:3)

我认为您发布的MSDN链接中的相关位是:

  

但是,Epsilon属性不是   一般的精度测量   双重型;它仅适用于Double   值为零的实例。

     

注意:Epsilon的值   财产不等同于机器   epsilon,代表鞋帮   由于的相对误差的界限   浮点运算中的舍入。

     

此值未定义为最小值   正数x,这样x + 1.0   不等于1.0,所以Double.Epsilon   不能用于“几乎平等”。   在这里没有任何常数   价值最小的框架   正数x,这样x + 1.0   不等于1.0。

我不得不说,这让我感到惊讶。我也认为Double.Epsilon相当于c / c ++中的DBL_EPSILON - 显然不是!

从我能看到的那个链接看起来似乎是在说“你需要自己为比较找出一个合适的价值”,这至少可以说是令人惊讶的。
也许更有知识的人可以澄清:)

答案 6 :(得分:2)

我使用以下

stdWrap

如果你想检查两个双打的平等性,那么&#39;和&#39; b&#39;,您可以使用

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;
    }

如果您想获得比较结果,请使用

(a-b).IsZero();

答案 7 :(得分:1)

比较双打的问题是,当你在两个不同的数学结果之间进行比较时,由于四舍五入的错误,它们没有评估到相同的值,它们会有一些差别......这是大于epsilon,边缘情况除外。使用可靠的epsilon值也很困难。有些人认为两个双精度相等,如果它们之间的差异小于某个百分比值,因为使用静态最小差异epsilon可能意味着当双精度本身为高或低时,你的差异太小或太大。

答案 8 :(得分:0)

以下是Silverlight Control Toolkit中包含两次的一些代码:

    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作为epsilon;在另一个他们使用1.192093E-07。你会想要选择自己的epsilon。

答案 9 :(得分:0)

没有选择你必须自己计算或定义自己的常量。

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

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