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

Плавающая точка, насколько я могу доверять меньше или больше сравнений?

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

Это сложный вопрос для фразы, поэтому я написал это, чтобы продемонстрировать это -

float a = random();
float b = random();  // always returns a number (no infinity or NaNs)

if(a < b){
    if( !(a < b + FLOAT_EPISILON) ) launchTheMissiles();
    buildHospitals();

}else if(a >= b){
    if( !(a >= b - FLOAT_EPISILON) ) launchTheMissiles();
    buildOrphanages();

}else{
    launchTheMissiles();  // This should never be called, in any branch
}

С учетом этого кода гарантируется, что launchTheMissiles() никогда не будет вызываться?

4b9b3361

Ответ 1

Если вы можете гарантировать, что a и b не являются NaN или бесконечностями, вы можете просто сделать:

if (a<b) {
    …
} else {
    …
}

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

Фактически, IEEE 754 был спроектирован таким образом, что сравнение значений non-infinity, отличных от NaN, одного и того же знака может быть выполнено с теми же операциями, что и нормальные целые числа (опять же, с ошибкой с нулем). Итак, в этом конкретном случае вы можете думать об этих числах как о "лучших целых числах".

Ответ 2

Короткий ответ, он никогда не будет вызван.

Если a<b, то a всегда будет меньше b плюс положительная сумма, какая бы она ни была. В этом случае проверка, если a меньше, чем b +, будет действительной.

Третий случай не будет достигнут.

Ответ 3

Стандарт IEEE 754 (с плавающей запятой) утверждает, что сложение или вычитание могут привести к положительной или отрицательной бесконечности, поэтому b + FLOAT_EPSILON и b - FLOAT_EPSILON могут привести к положительной или отрицательной бесконечности, если b - FLT_MAX или -FLT_MAX. В стандарте с плавающей запятой также указано, что бесконечность сравнивается, как и следовало ожидать, с FLT_MAX < + бесконечность, возвращающая true, и -FLT_MAX > -infinity.

Для более пристального рассмотрения формата с плавающей запятой и точности вопросов с практической точки зрения, я рекомендую взглянуть на книгу Криса Эриксона "Обнаружение столкновений в реальном времени" или в сообщениях Брюса Доусона по этой теме, последняя из которых (с приятной оглавление!) находится на http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/.

Ответ 4

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

Ответ 5

Как насчет меньше, чем проверка с помощью окна epsilon? если a меньше b, то a не может быть равно b

/**
 * checks whether a <= b with epsilon window
 */
template <typename T>
bool eq(T a, T b){
    T e = std::numeric_limits<T>::epsilon();
    return std::fabs(a-b) <= e;
}
/**
 * checks whether a < b with epsilon window
 */
template <typename T>
bool lt(T a, T b){
     if(!eq(a,b)){ // if a < b then a != b
         return a < b;
     }
     return false;
}
/**
 * checks whether a <= b with epsilon window
 */
template <typename T>
bool lte(T a, T b){
     if(eq(a,b)){
         return true;
     }
     return a < b;
}