59

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

如果您创建一个自定义算法来确定两个浮点数是否可以被视为相等,您必须使用一个大于 Epsilon 常数的值来确定两个值相等的可接受的绝对差值。(通常,差异幅度比 Epsilon 大很多倍。)

那么这真的不是一个可以用于比较的 epsilon 吗?我不太了解 MSDN 的措辞。

可以在这里的示例中用作 epsilon 吗?-浮动和双重比较最有效的方法是什么?

最后,这似乎真的很重要,所以我想确保我有一个可靠的平等实现,大于、小于、小于或等于,以及大于或等于。

4

9 回答 9

87

我不知道他们在写这篇文章时在抽什么。 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;
}

您必须注意,截断错误会累积。如果两者x都是y计算值,那么您必须增加 epsilon。

于 2010-03-09T18:50:05.487 回答
50

我想确保我对相等、大于、小于、小于或等于以及大于或等于有一个可靠的实现。

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

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

大概然后您正在使用二进制浮点算术,因为它打算使用:对物理量进行算术。

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

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

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

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

简而言之:你是这里唯一知道什么是合理误差容限的人,因为你是唯一知道你所操纵的数字首先来自哪里的人。考虑到您用于生产测量的设备的精度,请使用对您的测量有意义的任何误差容限。

于 2010-03-09T19:06:47.160 回答
12

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

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

如果您要比较的双精度值接近 1.0。那么最低有效位的值将接近 0.0000000000000001。如果您要比较的双精度值是千万亿,那么最低有效位的值可能高达一千。在这两种情况下,没有一个 epsilon 值可用于相等比较。

于 2010-03-09T18:21:53.030 回答
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;
}
于 2012-01-05T11:34:58.543 回答
4

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

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

bool IsApproximatelyEqual(double value, double permittedVariance);

超出了我的范围。

于 2010-03-09T18:13:21.970 回答
4

我使用以下

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'的相等性,你可以使用

(a-b).IsZero();

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

(a-b).Sign();
于 2017-10-11T07:52:38.377 回答
1

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

于 2010-03-09T18:23:46.583 回答
1

以下是 Silverlight 控制工具包中包含两次的一些代码:

    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-6epsilon;在另一个他们使用1.192093E-07. 您将要选择自己的 epsilon。

于 2010-03-09T19:26:15.623 回答
0

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

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

    while(one + result/2.0 != 1.0) {
        result/=2.0;
    }
    return result;
}
于 2014-08-12T10:08:05.973 回答