5

Как правильно сравнивать два числа типа float и double? Следующий способ часто говорит, что одинаковые числа различны:

float a = 0.00001001;
double b = 0.00001001;

if (a == b) {
  std::cout << "equal"; // не выводит equal
}

Мой вопрос отличается от дубликатов тем, что мне нужно знать, как правильно сравнить 2 числа типа float и double на C++, а не почему (не только почему) простое сравнение не работает. В привидённых в дубликатах ответах либо ответы для 2 одинаковых типов, либо не сказано как выбирать epsilon и т.д..

Hero
  • 51

2 Answers2

7
if (fabs(a - b) <= eps)

где eps - некая маленькая величина, вообще говоря - зависящая от порядка самих чисел, поэтому более корректно

if (fabs(a - b)/ max(fabs(a) + eps, fabs(b) + eps) <= eps)

Пример задания eps:

const
  FuzzFactor = 1000;
  SingleResolutionEps = 1E-7 * FuzzFactor;
  DoubleResolutionEps = 1E-15 * FuzzFactor;

Откуда это берётся - точность float 23 двоичных разряда или 7-8 десятичных, т.е. число имеет 7 верных десятичных цифр, поэтому меньше 1E-7 eps смысла нет делать.

Почему используется множитель FuzzFactor = 1000; - это расширение допуска, чёткого критерия его выбора нет, разработчики этой библиотеки решили так сделать, а вообще множитель можно выбирать в зависимости от желаемой погрешности в младших разрядах.

Для сравнения float и double по правилам сложения погрешностей следует использовать погрешность для менее точных float, т.е. порядка 1E-7 даже при приведении float к double, как предложил в комментарии @Grundy - ведь при этом приведении возникают дополнительные ничем не обеспеченные разряды с погрешностью в пределах всё тех же 1E-7.

Труды по точности float-арифметики: 1 2 Goldberg

magrif
  • 2,789
MBo
  • 53,555
  • 1
    Уточните, как вычислить правильный eps? ;-) – Kromster Nov 30 '18 at 08:24
  • 1
    .. .и как же установить значение для eps? – Kromster Nov 30 '18 at 08:29
  • 1
    А что за FuzzFactor? – Hero Nov 30 '18 at 08:30
  • Похоже, вы жертва того же заблуждения, что эпсилон это константа. Сравните, пожалуйста, float 0,000000000567 и float 0,000000000568 с использованием 1E-7 ;-) – Kromster Nov 30 '18 at 08:34
  • Если точность результата нужна до 1e-7, то для нас не имеет значения, что творится "на хвосте" и такие значения для нас равны – Alexander Chernin Nov 30 '18 at 08:36
  • @Kromster Кто жертва? Что не так с этим сравнением? По приведенной формуле 1E-12/5E-10 = 0.002 > 1e-7 – MBo Nov 30 '18 at 08:38
  • @AlexanderChernin вы ввели новую сущность - точность результата, к которой видимо предъявили требования быть 1е-7 - т.е. вы жестко задали Эпсилон для некоторой задачи. Заметьте, что в вопросе этого нет. Вопрос спрашивает, как сравнить. – Kromster Nov 30 '18 at 08:39
  • Потом был вопрос, а как выбирать Эпсилон и мы все вместе дали ответ. Зачетку давать, или на пересдачу прийти? – Alexander Chernin Nov 30 '18 at 08:41
  • @MBo похоже вы правы, извиняюсь. Уточните плиз, что такое FuzzFactor. – Kromster Nov 30 '18 at 08:42
  • @Hero, Например: https://ru.cppreference.com/w/cpp/types/numeric_limits/epsilon – Grundy Nov 30 '18 at 08:44
  • 1
    @Grundy там в примере не такое сравнение, как в ответе. Почему? Для какого типа брать std::numberic_limits: float или double? – Hero Nov 30 '18 at 08:47
  • @FuzzFactor совокупность всех ошибок, кроме ошибки округления. тут взята с потолка.

    К примеру если вы умножаете 2 флоата, то ошибка уже E-6 и так далее

    – eri Nov 30 '18 at 08:48
  • @Hero, обрати внимание, что по ссылке сравниваются параметры с одинаковым типом. Если типы разные, очевидно, нужно привести к какому-либо одному. – Grundy Nov 30 '18 at 08:50
  • я бы добавил что правильный эпсилон можно посчитать по вузовским методичкам в разделе "ПОГРЕШНОСТИ КОСВЕННЫХ ИЗМЕРЕНИЙ" – eri Nov 30 '18 at 08:56
2

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

А машинный эпсилон это характеристика данной вычислительной системы.

pepsicoca1
  • 5,019