Назад к вопросам
Middle
87
questionbank

Можно ли использовать числа с плавающей запятой в качестве ключей контейнеров?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Не рекомендуется.

Причины:

  1. Проблемы сравнения: Числа с плавающей запятой не всегда могут быть точно представлены в двоичном виде. Сравнение на точное равенство a == b может дать ложный результат из-за погрешности представления. Контейнеры на основе деревьев (ассоциативные массивы, множества) и хэш-таблицы полагаются на точное сравнение либо на вычисление хэша основе точного значения.
  2. Нестабильность хэша: Хэш-значение числа с плавающей запятой, вычисленное на основе его двоичного представления, не будет устойчивым к малым изменениям значения. Близкие по значению числа могут иметь очень разные хэши, и одинаковые по значению числа (полученные разными вычислениями из-за погрешностей) могут иметь разные хэши. Это приводит к низкой эффективности хэш-таблиц (например, std::unordered_map).
  3. Поведение NaN и Infinity: Специальные значения (NaN, Infinity) имеют неопределенное или нестандартизированное поведение при сравнении и хэшировании, что может привести к непредсказуемым результатам.

Вместо этого можно использовать:

  • Целочисленное представление, если это применимо (например, хранить значения в сотых долях).
  • Специализированные классы для сравнения или хэширования с учетом допустимой погрешности (epsilon), но это усложняет использование стандартных контейнеров.
  • boost::float_column, если используется библиотека Boost.

Пример проблемы сравнения:

#include <iostream>

int main() {
    double a = 0.1 + 0.2;
    double b = 0.3;
    if (a == b) {
        std::cout << "0.1 + 0.2 == 0.3" << std::endl; // Может не вывестись
    } else {
        std::cout << "0.1 + 0.2 != 0.3 (из-за погрешности)" << std::endl;
    }
    return 0;
}