Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

Просто заметил этот вопрос.

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

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

Ответ 2

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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