Как правильно использовать прибл. ()? - PullRequest
4 голосов
/ 02 января 2012

Сначала я думал, что могу рассчитывать только на максимальную относительную разницу, но я ошибался.Например, если a = 0.0 и b = 0.5, их относительная разница равна 1.0.В этом случае approxEquals(lhs, rhs, maxRelDiff, maxAbsDiff) полагается на максимальную абсолютную разницу, чтобы определить, равны ли два числа с плавающей запятой.

Два вопроса:

  1. как мне подойтис новой парой максимальной относительной и абсолютной разности, если значение по умолчанию (1e-2, 1e-5) недостаточно точное?Как 1e-2 и 1e-5 были выбраны в качестве значений по умолчанию?Например, если я выберу 1e-4 в качестве моей максимальной относительной разницы, какова максимальная абсолютная разница?

  2. Как настроить максимальные значения относительной и абсолютной разности для правильной работы с floats и doubles?

Ответы [ 2 ]

1 голос
/ 02 января 2012

проверка исходного кода дает мне это (я вырезал реализации для диапазонов)

bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 1e-5)
{   

    if (rhs == 0)
    {
        return fabs(lhs) <= maxAbsDiff;
    }
    static if (is(typeof(lhs.infinity)) && is(typeof(rhs.infinity)))
    {
        if (lhs == lhs.infinity && rhs == rhs.infinity ||
            lhs == -lhs.infinity && rhs == -rhs.infinity) return true;
    }
    return fabs((lhs - rhs) / rhs) <= maxRelDiff
        || maxAbsDiff != 0 && fabs(lhs - rhs) <= maxAbsDiff;
}

эта последняя строка - то, что нам нужно изучить:

return fabs((lhs - rhs) / rhs) <= maxRelDiff
        || maxAbsDiff != 0 && fabs(lhs - rhs) <= maxAbsDiff;

другими словами, функция возвращает true, если числа либо относительно отличаются не более чем на коэффициент maxRelDiff ИЛИ абсолютно отличаются не более чем на maxAbsDiff

, поэтому при использовании maxRelDiff из 0.01 (или 1E-2) сравнивается с точностью до 2 (десятичных) цифр

и при использовании maxAbsDiff, отличного от 0, допускаются числазначение, близкое к 0, считается равным, хотя относительная разница больше, чем maxRelDiff

edit : сначала необходимо решить, насколько точным должно быть сравнение, и выбрать maxRelDiff на основезатем определите, в какой точке число должно быть равно 0

, с примерами в комментариях:

approxEqual(1+1e-10, 1.0, 1e-10, 1e-30) 
approxEqual(1+1e-10, 1.0, 1e-9, 1e-30)

. Здесь сравниваются значения, близкие к 1, поэтому maxRelDiff имеет преимущество и выбираетлюбой maxAbsDiff (ниже maxRelDiff) не изменитсячто-нибудь

approxEqual(0, 1e-10, 1e-10, 1e-30) 
approxEqual(0, 1e-9, 1e-9, 1e-30)

это сравнивает значения от 0 до 0, поэтому RelDiff (fabs((lhs - rhs) / rhs)) будет 1 и maxAbsDiff козыри

0 голосов
/ 02 января 2012

Хотя я не могу ответить на ваш первоначальный вопрос, лично я использую fabs для сравнений с плавающей точкой:

return fabs(f1 - f2) < 0.10;
...