Хорошая ли идея использовать NaN с плавающей запятой IEEE754 для значений, которые не установлены?

StackOverflow https://stackoverflow.com/questions/1036686

Вопрос

Хорошая ли идея использовать NaN с плавающей запятой IEEE754 (не число) для значений, которые не определены по нематематическим причинам?

В нашем случае они еще не установлены, поскольку значения не получены от какого-либо другого устройства.Контекст представляет собой встроенную систему, использующую значения IEC1131 REAL32. Редактировать: Язык программирования — C, поэтому мы, скорее всего, будем использовать NAN и isnanf(x) из C99.Хотя нам могут потребоваться некоторые дополнительные искажения, чтобы перенести их на уровень совместимости с нашей ОС.

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

Кажется, что использование NaN — чистое решение, но, может быть, это больше хлопот, чем пользы, и нам следует выбрать какое-то другое значение?

Это было полезно?

Решение

Только что заметил этот вопрос.

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

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

Другие советы

NaN — разумный выбор для предложения «нет значения» (например, язык программирования D использует их для неинициализированных значений), но поскольку любые сравнения, включающие их, будут ложными, вы можете получить несколько сюрпризов:

  • if (result == DEFAULT_VALUE), не будет работать должным образом, если DEFAULT_VALUE является NaN, как упомянул Джон.

  • Они также могут вызвать проблемы с проверкой диапазона, если вы не будете осторожны.Рассмотрим функцию:

bool isOutsideRange(double x, double minValue, double maxValue)
{
    return x < minValue || x > maxValue;
}

Если x равно NaN, эта функция неправильно сообщит, что x находится между minValue и maxValue.

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

[Редактировать:Первоначально мне удалось ввести выше «любые сравнения, включающие их, будут истинными», но это не то, что я имел в виду, и это неправильно, все они ложны, кроме NaN != NaN, что верно]

Я использовал NaN в аналогичных ситуациях только из-за этого: обычное значение инициализации по умолчанию 0 также является допустимым значением. До сих пор NaN работают нормально.

Кстати, хороший вопрос, почему значение инициализации по умолчанию обычно (например, в примитивных типах Java) 0, а не NaN. Разве это не может быть 42 или что-то еще? Интересно, каково обоснование нулей.

Я думаю, что это вообще плохая идея. Следует иметь в виду, что большинство процессоров обрабатывают Nan гораздо медленнее, чем «обычные». плавать. И трудно гарантировать, что у вас никогда не будет Nan в обычных условиях. Мой опыт работы с цифровыми вычислениями заключается в том, что они часто приносят больше проблем, чем они того стоят.

Правильное решение состоит в том, чтобы избежать кодирования "отсутствия значения" в поплавке, но сигнализировать об этом по-другому. Это не всегда практично, в зависимости от вашей кодовой базы.

Будьте осторожны с NaN ... они могут распространяться как лесной пожар, если вы не будете осторожны.

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

D использует это в качестве обоснования для предоставления числам NaN по умолчанию. (С чем я не уверен, я согласен.)

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

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

Просто помните, что в зависимости от вашей среды вам, вероятно, понадобится особый способ обнаружения NaN (не просто используйте if (x == float.NaN) или любой другой эквивалентный вам вариант.)

Это звучит как хорошее применение для нанс для меня. Жаль, что я не думал об этом ...

Конечно, они должны распространяться как вирус, вот в чем дело.

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

Использование NaN в качестве значения по умолчанию является разумным.

Обратите внимание, что некоторые выражения, такие как (0.0 / 0.0), возвращают NaN.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top