Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Переходим на https. Просьба писать обо всех замеченных неисправностях.
  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Правильное оформление сравнения чисел с плавающей запятой.  (Прочитано 1070 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Aether
Молодой специалист

ru
Offline Offline
Пол: Мужской

« : 07-02-2017 19:01 » 

Доброго вечера.

Хочу поинтересоваться, как правильно на "С" описывать операции сравнения чисел с плавающей запятой?

Суть в чём, например, в ходе вычислений получился "0", справедлива ли запись:
Код: (C)
float fT;
...
if (fT == 0.) ...
Как эта же запись отреагирует на "-0."? Как отделить сравнение "+0." от "-0."?

Справедлива ли проверка:
Код: (C)
if (!fT) ...
Ведь "-0." не является с точки зрения бит нулевым: (float)0x80000000.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 07-02-2017 22:17 » 

Боян, блин...
http://wiki.shelek.ru/index.php/FAQ:ANSI_CPP:%D1%81%D1%80%D0%B0%D0%B2%D0%BD%D0%B8%D1%82%D1%8C_%D0%B4%D0%B2%D0%B0_%D1%87%D0%B8%D1%81%D0%BB%D0%B0_%D1%82%D0%B8%D0%BF%D0%B0_double
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.

Хз, я не очень просто не очень во всё это верю, во всякие там сатурны и прочую поебень.
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #2 : 08-02-2017 04:52 » 

в Qt даже отдельную функцию добавили qFuzzyCompare

Подозреваю, что в std:: тоже что-то подобное давно уже есть, не проверял )
Записан

Aether
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 08-02-2017 09:45 » 

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

У меня задача сравнения с нулём, например, вычисляем функцию y(x) = A + B / x. При x == 0 будет деление на ноль, и его нужно избежать. Как в этом случае отработать? В случае вычисления пределов часто появляется -0. Как быть здесь?

в Qt даже отдельную функцию добавили qFuzzyCompare
Кстати:
Цитата
bool qFuzzyCompare(double p1, double p2)

Compares the floating point value p1 and p2 and returns true if they are considered equal, otherwise false.

Note that comparing values where either p1 or p2 is 0.0 will not work, nor does comparing values where one of the values is NaN or infinity. If one of the values is always 0.0, use qFuzzyIsNull instead. If one of the values is likely to be 0.0, one solution is to add 1.0 to both values.

bool qFuzzyIsNull(double d)

Returns true if the absolute value of d is within 0.000000000001 of 0.0.
Не совсем понял: зачем их вообще ввели, ведь точность может быть хуже и сравнивать нужно с большим её срезом.


Итак, небольшой тест:
Код: (C)
#include <stdio.h>

int main(int argc, char* argv[]) {

    char pcPlusZero[8] = {0x00, 0x00, 0x00, 0x00, \
                          0x00, 0x00, 0x00, 0x00};

    char pcMinusZero[8] = {0x00, 0x00, 0x00, 0x00, \
                           0x00, 0x00, 0x00, 0x80};

    double* pdPlusZero = (double*)pcPlusZero;
    double* pdMinusZero = (double*)pcMinusZero;

    printf("Plus zero: %f\n", *pdPlusZero);
    printf("Minus zero: %f\n", *pdMinusZero);

    if (*pdPlusZero == (double)0.) printf("Test 1: Plus zero equal zero.\n");

    if (*pdMinusZero == (double)0.) printf("Test 2: Minus zero equal zero.\n");

    if (*pdPlusZero == *pdMinusZero) printf("Test 3: Plus zero equal Minus zero.\n");

    if (*pdPlusZero) printf("Test 4: Plus zero is not \"zero\".\n");

    if (*pdMinusZero) printf("Test 5: Minus zero is not \"zero\".\n");

    if (!*pdPlusZero) printf("Test 6: Plus zero is \"zero\".\n");

    if (!*pdMinusZero) printf("Test 7: Minus zero is \"zero\".\n");

    if (*pdPlusZero == (double)1.) printf("Test 8: Plus zero equal 1.\n");

    if (*pdMinusZero == (double)1.) printf("Test 9: Minus zero equal 1.\n");

    long long* pllPlusZero = (long long*)pcPlusZero;

    if (*pllPlusZero) printf("Test 10: Long long plus zero is not \"zero\".\n");

    long long* pllMinusZero = (long long*)pcMinusZero;

    if (*pllMinusZero) printf("Test 11: Long long minus zero is not \"zero\".\n");

    return 0;
}

Результат:
Plus zero: 0.000000
Minus zero: -0.000000
Test 1: Plus zero equal zero.
Test 2: Minus zero equal zero.
Test 3: Plus zero equal Minus zero.
Test 6: Plus zero is "zero".
Test 7: Minus zero is "zero".
Test 11: Long long minus zero is not "zero".
Записан
darkelf
Молодой специалист

ua
Offline Offline

« Ответ #4 : 08-02-2017 10:37 » 

У меня задача сравнения с нулём, например, вычисляем функцию y(x) = A + B / x. При x == 0 будет деление на ноль, и его нужно избежать. Как в этом случае отработать? В случае вычисления пределов часто появляется -0. Как быть здесь?
Для проверки на +0 и -0 в C99/C11 есть fpclassify(), которая в таком случае должна вернуть FP_ZERO.

А вообще, как я понял, по-новому советуют делать что-то вроде такого:
Код: (C)
#include <fenv.h>
#include <math.h>
#include <stdio.h>

int main(int arhc, char* argv[])
{ double rez, one = 1.0, zero = 0.0;
  int ex;

  feclearexcept(FE_ALL_EXCEPT);

  rez = one / zero;

  ex = fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);

  if (ex & FE_DIVBYZERO)
    printf("zero divide\n");
  if (ex & FE_INVALID)
    printf("invalid\n");
  if (ex & FE_OVERFLOW)
    printf("overflow\n");
  if (ex & FE_UNDERFLOW)
    printf("undeflow\n");

  return 0;
}
« Последнее редактирование: 08-02-2017 11:11 от darkelf » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines