Подтвердить что ты не робот

Double.Epsilon для равенства, больше, меньше, меньше или равно, больше или равно

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

Если вы создадите собственный алгоритм, который определяет, будут ли две плавающие точки числа можно считать равными, вы должно использовать значение, которое больше, чем константа Эпсилона для установления допустимый абсолютный запас разница для двух значений считается равным. (Как правило, это разница разницы во много раз больше, чем Эпсилон.)

Так разве это не эпсилон, который можно было бы использовать для сравнений? Я действительно не понимаю формулировку MSDN.

Может ли он использоваться в качестве примера в примерах здесь? - Каков наиболее эффективный способ для плавающего и двойного сравнения?

И, наконец, это кажется действительно важным, поэтому я хотел бы убедиться, что у меня есть четкая реализация для равенства, больше, меньше, меньше или равно, и больше или равно.

4b9b3361

Ответ 1

Я не знаю, что они курили, когда они это писали. Double.Epsilon - наименьшее представляемое значение, не являющееся денормальным значением с плавающей запятой, которое не равно 0. Все, что вы знаете, это то, что если есть ошибка усечения, оно всегда будет больше этого значения. Гораздо больше.

Тип System.Double может представлять значения с точностью до 15 цифр. Итак, простая оценка первого порядка, если двойное значение x равно некоторой константе, - это использовать эпсилон постоянной * 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;
}

Вы должны следить, хотя ошибки усечения могут накапливаться. Если значения x и y являются вычисленными значениями, вам необходимо увеличить эпсилон.

Ответ 2

Я хотел бы убедиться, что у меня есть твердая реализация для равенства, больше, меньше, меньше или равно, и больше или равно.

Вы используете двоичную арифметику с плавающей запятой.

Двоичная арифметика с плавающей запятой была разработана для представления физических величин, таких как длина, масса, заряд, время и т.д.

Предположительно, вы используете двоичную арифметику с плавающей запятой, как и предполагалось использовать: для выполнения арифметики по физическим величинам.

Измерения физических величин всегда имеют определенную точность, в зависимости от точности устройства, используемого для их измерения.

Поскольку вы являетесь тем, кто предоставляет значения для количества, которое вы манипулируете, вы тот, кто знает, что такое "бары ошибок" на этом количестве. Например, если вы предоставляете количество "высота здания 123,56 метра", то вы знаете, что это точно с сантиметром, но не с микрометром.

Следовательно, при сравнении двух величин для равенства желаемая семантика состоит в том, чтобы сказать: "являются ли эти две величины равными в пределах баров ошибок, заданных каждым измерением?"

Итак, теперь у нас есть ответ на ваш вопрос. Что вы должны делать, это следить за тем, какая ошибка на каждом количестве; например, высота здания "находится в пределах 0,01 от 123,56 метров", потому что вы знаете, насколько точно это измерение. Если вы затем получите другое измерение, которое составляет 123.5587, и хотите знать, являются ли эти два измерения "равными" в пределах допусков ошибок, затем выполните вычитание и посмотрите, попадает ли он в допуски ошибок. В этом случае это так. Если измерения на самом деле были точными для микрометра, то они не равны.

Вкратце: вы единственный человек, который знает, какие разумные допуски ошибок есть, потому что вы единственный человек, который знает, где фигуры, с которыми вы манипулируете, пришли в первую очередь. Используйте любые допуски ошибок, которые имеют смысл для ваших измерений, учитывая точность оборудования, которое вы использовали для его изготовления.

Ответ 3

Если у вас есть два двойных значения, близких к 1.0, но они отличаются только наименее значимыми битами, то разница между ними будет на много порядков больше Double.Epsilon. Фактически разница составляет 324 десятичных порядка величины. Это связано с эффектом экспоненциальной части. Double.Epsilon имеет на нем огромный отрицательный показатель, в то время как 1.0 имеет показатель нуля (после устранения смещений, конечно).

Если вы хотите сравнить два одинаковых значения для равенства, вам нужно будет выбрать собственное значение эпсилона, соответствующее размерам величин порядка величин сравниваемых значений.

Если двойные значения, которые вы сравниваете, близки к 1.0. Тогда значение наименее значимого бита будет около 0,0000000000000001. Если двойные значения, которые вы сравниваете, находятся в квадриллионах, то значение наименее значимого бита может составлять до тысячи. Ни одно значение для epsilon не может использоваться для сопоставлений равенства в обоих этих обстоятельствах.

Ответ 4

Я просто сделал это - используя идею Кента Богартса.

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

Ответ 5

Его можно использовать для сравнений, предполагая, что вы хотите, чтобы оба значения были либо ровно равными, либо имели наименьшую представляемую разницу для двойного типа. Вообще говоря, вы хотели бы использовать число больше, чем double.Epsilon, чтобы проверить, являются ли два удвоения приблизительно равными.

Почему инфраструктура .NET не определяет что-то вроде

bool IsApproximatelyEqual(double value, double permittedVariance);

находится вне меня.

Ответ 6

Я думаю, что соответствующие биты в ссылке MSDN, которые вы разместили, следующие:

Однако свойство Epsilon не является общая мера точности Двойной тип; это относится только к Double экземпляры с нулевым значением.

Примечание: значение Epsilon свойство не эквивалентно машине эпсилон, который представляет собой верхний граница относительной ошибки, обусловленной округление в арифметике с плавающей запятой.

Это значение не определяется как наименьшее положительное число x, такое, что x + 1,0 не равно 1.0, поэтому Double.Epsilon не может использоваться для "почти равенства". В структура, значение которой наименьшее положительное число x, такое, что x + 1,0 не равно 1.0.

Я должен сказать, что меня удивляет. Я тоже предположил, что Double.Epsilon был эквивалентом DBL_EPSILON в c/С++ - явно нет!

Из того, что я могу прочитать по этой ссылке, кажется, говорится: "Вам нужно правильно оценить ценность для сравнений", что, по меньшей мере, удивительно. Возможно, кто-то более осведомленный может прояснить:)

Ответ 7

Проблема сравнения двойников заключается в том, что при сравнении двух разных математических результатов, которые равны, но которые из-за ошибок округления не оцениваются с одинаковым значением, они будут иметь некоторую разницу... которая больше, чем epsilon, за исключением случаев краев. И использование надежного эпсилонного значения также затруднено. Некоторые люди считают, что два удвоения равны, если разница между ними меньше некоторого процентного значения, так как использование статической минимальной разницы epsilon может означать, что ваши различия слишком малы или велики, когда сам double является высоким или низким.

Ответ 8

Вот код, который дважды включался в 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. Вы захотите выбрать свой собственный эпсилон.

Ответ 9

Нет выбора, который вы должны сами вычислить или определить собственную константу.

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

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

Ответ 10

Я использую следующие

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();