Для чего может использоваться std:: numeric_limits<double>:: epsilon ()?

  unsigned int updateStandardStopping(unsigned int numInliers, unsigned int totPoints, unsigned int sampleSize)
    {
        double max_hypotheses_=85000;
        double n_inliers = 1.0;
        double n_pts = 1.0;
        double conf_threshold_=0.95

        for (unsigned int i = 0; i < sampleSize; ++i)
        {
            n_inliers *= numInliers - i;//n_linliers=I(I-1)...(I-m+1)
            n_pts *= totPoints - i;//totPoints=N(N-1)(N-2)...(N-m+1)
        }
        double prob_good_model = n_inliers/n_pts;

        if ( prob_good_model < std::numeric_limits<double>::epsilon() )
        {
            return max_hypotheses_;
        }
        else if ( 1 - prob_good_model < std::numeric_limits<double>::epsilon() )
        {
            return 1; 
        }
        else 
        {
            double nusample_s = log(1-conf_threshold_)/log(1-prob_good_model);
            return (unsigned int) ceil(nusample_s); 
        }
    }

Вот заявление о выборе:

if ( prob_good_model < std::numeric_limits<double>::epsilon() )
{...}

Насколько я понимаю, суждение такое же, как (или приближение к)

prob_good_model < 0

Так ли я прав и где std::numeric_limits<double>::epsilon() можно использовать помимо этого?

2 ответа

Решение

Смысл эпсилона состоит в том, чтобы вам было (довольно) легко вычислить наименьшее различие, которое вы можете видеть между двумя числами.

Вы обычно не используете это точно как есть все же. Вы должны масштабировать его на основе величин чисел, которые вы сравниваете. Если у вас есть два числа около 1e-100, то вы будете использовать что-то порядка: std::numeric_limits<double>::epsilon() * 1.0e-100 как ваш стандарт сравнения. Аналогичным образом, если ваши числа около 1e+100, ваш стандарт будет std::numeric_limits<double>::epsilon() * 1e+100,

Если вы попытаетесь использовать его без масштабирования, вы можете получить совершенно неверные (совершенно бессмысленные) результаты. Например:

if (st::abs(1e-100 - 1e-200) < std::numeric_limits<double>::epsilon())

Да, это будет отображаться как "истина" (то есть, говоря, что два равны), даже если они отличаются на 100 порядков. В другом направлении, если числа намного больше 1, сравнение с (немасштабированным) эпсилоном эквивалентно if (x != y)- это не оставляет места для ошибок округления вообще.

По крайней мере, по моему опыту, epsilon указанный для типа с плавающей запятой, часто не очень полезен. При правильном масштабировании он сообщает вам наименьшую разницу, которая может быть между двумя числами заданной величины (для конкретной реализации с плавающей запятой).

В реальном использовании, однако, это относительно мало реального использования. Более реалистичное число обычно будет основываться на точности входных данных и оценке степени точности, которую вы, вероятно, потеряете из-за округления (и тому подобное).

Например, предположим, что вы начали со значений, измеренных с точностью до 1 части на миллион, и выполнили всего несколько вычислений, поэтому вы полагаете, что, возможно, потеряли целых 2 цифры точности из-за ошибок округления. В этом случае интересующий вас "эпсилон" составляет примерно 1e-4 и масштабируется до величины числа, с которым вы имеете дело. То есть в этих обстоятельствах можно ожидать значимости порядка 4 цифр точности, поэтому, если вы видите разницу в первых четырех цифрах, это, вероятно, означает, что значения не равны, но если они различаются только в пятых (или более поздних) цифрах вы, вероятно, должны рассматривать их как равные.

Тот факт, что используемый вами тип с плавающей запятой может представлять (например) 16 цифр точности, не означает, что каждое используемое вами измерение будет почти точным - на самом деле, это относительно редко что-либо, основанное на физическом измерения имеют надежду даже приблизиться к этому точному. Однако он дает вам предел того, на что вы можете рассчитывать из расчета - даже если вы начнете со значения, которое, скажем, до 30 цифр, самое большее, на что вы можете надеяться после расчета, будет определено std::numeric_limits<T>::epsilon,

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

Допустим, вы используете1/xгде-то, но ваш диапазон x равен [0, n[. вы можете использовать1/(x + std::numeric_limits<double>::epsilon())вместо этого так, чтобы 0 все еще был определен. При этом вы должны быть осторожны с тем, как используется значение, оно может не работать для каждого случая.

Другие вопросы по тегам