Является ли хорошей идеей использовать NaN IEEE754 с плавающей точкой для значений, которые не установлены? - PullRequest
13 голосов
/ 24 июня 2009

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

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

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

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

Ответы [ 9 ]

11 голосов
/ 15 октября 2009

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

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

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

4 голосов
/ 24 июня 2009

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: это удобно, когда вы не хотите полагаться на вызывающих, проверяющих значение, например.

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

3 голосов
/ 24 июня 2009

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

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

3 голосов
/ 24 июня 2009

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

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

2 голосов
/ 24 июня 2009

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

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

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

1 голос
/ 24 июня 2009

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

0 голосов
/ 11 июля 2009

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

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

0 голосов
/ 11 июля 2009

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

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

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

0 голосов
/ 24 июня 2009

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

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

...