Программирование SwiftSwift CoreРазработчик приложений на Swift

Как трактуется сравнение значения NaN с самим собой в Swift?

Как трактуется сравнение значения NaN с самим собой в Swift?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

В Swift значение NaN не равно самому себе: сравнение NaN с NaN через == даёт false, а через !=true. Это соответствует семантике стандарта IEEE 754 для некорректных или неопределённых результатов вычислений с плавающей точкой.

Исторический контекст

NaN означает «не число» и используется типами Float и Double для представления результата, который нельзя выразить обычным числом, например результата недопустимой операции. Такое специальное значение появилось в стандарте IEEE 754, чтобы вычисления могли продолжаться без немедленного исключения на каждом промежуточном некорректном результате.

Постановка проблемы

Наивная проверка равенства не подходит для обнаружения NaN. Условие сравнения значения с самим собой неожиданно ложно, поэтому логика вида «если значение не равно самому себе, значит произошла ошибка» хотя и может работать как низкоуровневый приём, плохо выражает намерение и усложняет поддержку.

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

Подробное решение

Для проверки следует использовать свойство isNaN, а не сравнение с самим собой. Операции сравнения ==, < и > с NaN не подтверждают обычное числовое отношение: равенство возвращает false, а оба неравенства порядка также возвращают false.

let value = Double.nan print(value == value) // false print(value != value) // true print(value.isNaN) // true

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

Важно отличать NaN от бесконечности: isNaN проверяет только NaN, а isInfinite — положительную или отрицательную бесконечность. Если бизнес-логика допускает только конечные значения, проверяйте isFinite.

Ситуация из практики

Сервис получает измерения датчика и сортирует их по величине. Один из элементов оказался NaN. Простая сортировка с обычным оператором < имеет проблему: для NaN оба сравнения порядка могут быть ложными, поэтому компаратор не формирует корректный строгий порядок.

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

Для измерений, которые нельзя использовать в расчётах, предпочтительно отклонять NaN на входе и возвращать диагностическую ошибку. Так система не переносит проблему в отчёты и последующие вычисления.

Что кандидаты часто упускают

1. Вопрос: Чем NaN отличается от положительной или отрицательной бесконечности?

NaN означает отсутствие определённого числового результата, тогда как бесконечность представляет значение, вышедшее за конечный диапазон типа, либо результат соответствующей операции. Для них используются разные проверки: isNaN и isInfinite; если нужны только обычные конечные числа, применяется isFinite.

2. Вопрос: Почему сортировка массива с NaN требует специального правила?

Оператор < с NaN не задаёт нормальный порядок: сравнение NaN с любым числом, включая другим NaN, не возвращает ожидаемую пару «меньше или больше». Поэтому компаратор на основе одного < может нарушить требования к строгому слабому порядку. Нужно заранее удалить NaN либо явно определить, где он располагается относительно остальных элементов.

3. Вопрос: Как NaN распространяется по цепочке вычислений и как ограничить последствия?

Большинство арифметических операций с NaN дают NaN, поэтому одно некорректное промежуточное значение может сделать бесполезным весь итоговый расчёт. Практический способ контроля — проверять isFinite или отдельно isNaN после операций, на границах ввода и перед записью результата. Это позволяет обнаружить источник ошибки раньше, чем NaN попадёт в хранилище, UI или аналитический отчёт.