Есть ли двойное значение, которое останется само собой, несмотря на любые вычисления, примененные к нему? - PullRequest
1 голос
/ 09 ноября 2011

На платформах Windows XP..7 для наборов команд x86, использующих стандартный C ++ или компилятор Microsoft, есть ли значение, которое я могу присвоить двойному, которое, когда к нему применяются другие вычисления, всегда будет приводить к тому же значение?

, например

const double kMagicValue = ???;
double x = kMagicValue;
cout << x * 9.1; // still outputs kMagicValue

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

Я спрашиваю, потому что у меня есть ряд функций, которые пытаются вычислить удвоение для заданного входа, а для некоторых входов «без ответа (NAN)» является хорошим выходом (концептуально).

И я хочу быть в состоянии быть ленивым и связывать воедино вычисления, которые должны, если какая-либо часть приведет к NAN, привести к целому как NAN (т.е. kMagicValue).

Ответы [ 4 ]

3 голосов
/ 09 ноября 2011

Любая операция с плавающей запятой, включающая NaN, приводит к NaN снова (насколько мне известно).Более того, NaN сравнивает неравномерно с самим собой, и оно уникально среди поплавков IEEE754 с этим свойством.Итак, чтобы проверить это:

bool is_nan(double x) { return x != x; }

Если у вас есть поддержка C ++ 11, вы можете вместо этого использовать std::isnan(x) != 0 или std::fpclassify(x) == std::FP_NAN из <cmath> [спасибо @James Brock].

Чтобы сделать это:

double make_nan() {
  assert(std::numeric_limits<double>::has_quiet_NaN);
  return std::numeric_limits<double>::quiet_NaN();
}
3 голосов
/ 09 ноября 2011

Тихий NaN должен делать просто отлично. Вы можете получить его из std::numeric_limits<double>::quiet_NaN(), включив заголовок <limits>. Существует также сигнализация NaN, но ее использование обычно приводит к исключению.

Помните, однако, что вы не можете просто использовать mydouble == qNaN, поскольку NaN сравнивает ничего не равный, даже самого себя. Вы должны использовать это свойство NaN для проверки: bool isNaN = mydouble != mydouble;.

2 голосов
/ 09 ноября 2011

Вы не должны полагаться на NaN, чтобы сделать работу. Он всегда будет сравнивать false с любым значением, в том числе и с самим собой, и вы должны убедиться, что платформа в определенной степени учитывает семантику IEEE754 (это включает в себя наличие NaN в первую очередь).

Смотрите там ужасные истории: Отрицательный NaN - это не NaN?

Если вам действительно нужен такой подход, и вы достаточно уверены в поддержке IEEE754, обязательно скомпилируйте с /fp:precise (поскольку вы используете MSVC), чтобы компилятор не оптимизировал такие вещи, как 0 * NaN. Помните, что это может повлиять на производительность.

Чтобы получить NaN,

std::numeric_limits<double>::quiet_NaN()

Для проверки на NaN

inline bool is_NaN(double x) { return !(x == x); }

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

Правильно использовать boost::optional<double>, но в некоторых местах он может быть немного многословным

[Кроме того, язык Haskell имеет первоклассную поддержку для такого потока управления, если C ++ не является обязательным параметром, Maybe, вы можете попробовать его.]

2 голосов
/ 09 ноября 2011

На самом деле существует специальное значение с плавающей запятой, называемое Not-A-Number (NaN). Любое выражение с включенным NaN вернет NaN.

#include <limits>
numeric_limits<double>::quiet_NaN()

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...