Используете NaN в C++?

Как лучше всего использовать NaN в C++?

Я нашел std::numeric_limits<double>::quiet_NaN() и std::numeric_limits<double>::signaling_NaN(). Я хотел бы использовать signaling_NaN для представления неинициализированной переменной следующим образом:

double diameter = std::numeric_limits<double>::signaling_NaN();

Однако это сигнализирует (вызывает исключение) о назначении. Я хочу, чтобы он создавал исключение при использовании, а не при назначении.

Есть ли способ использовать signaling_NaN без создания исключения при назначении? Есть ли хорошая портативная альтернатива signaling_NaN, которая будет вызывать исключение с плавающей запятой при использовании?

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

Jeffrey Martinez 25.10.2008 04:08

@JeffreyMartinez: Это не обычное исключение C++, если вы так думаете. Это исключение с плавающей запятой: см. Примечания здесь.

bames53 05.11.2012 19:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
33
2
33 547
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Вы можете записать сигнальный NaN в переменную, не вызывая исключения, примерно так (nb: непроверено)

void set_snan( double &d )
{
    long long *bits = (long long *)&d;
    *bits = 0x7ff0000080000001LL;
}

Он будет работать в большинстве мест, но нет, он не на 100% портативен.

В вашей реализации C++ может быть API для доступа к среде с плавающей запятой для проверки и удаления определенных исключений с плавающей запятой. См. мой ответ на связанный вопрос для получения дополнительной информации.

Что ж, глядя на определение как тихого, так и сигнального NaN, я не вижу никакой разницы.

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

Если вы хотите напрямую назначить NaN:

double value = _Nan._Double;

Что означает сигнализация NAN, так это то, что когда процессор встречает ее, выдается сигнал (отсюда и название). Если вы хотите обнаружить неинициализированные переменные, то повышение уровня предупреждения в вашем компиляторе обычно обнаруживает все пути, в которых используются неинициализированные значения. В противном случае вы можете использовать класс-оболочку, в котором хранится логическое значение, указывающее, инициализировано ли значение:

template <class T>
class initialized {
    T t;
    bool is_initialized;
public:
    initialized() : t(T()), is_initialized(false) { }
    initialized(const T& tt) : t(tt), is_initialized(true) { }
    T& operator=(const T& tt) { t = tt; is_initialized = true; return t; }
    operator T&() {
         if (!is_initialized)
             throw std::exception("uninitialized");
         return t; 
   }
};
boost::optional<T> - хорошая альтернатива этому и хорошо работает для возвращаемых значений, локальных переменных и членов. Кроме того, он не вызывает конструктор по умолчанию и работает по большей части со ссылочными типами.
rvalue 08.12.2011 07:06
Ответ принят как подходящий

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

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

Так что кажется, что Решение Мотти действительно лучший выбор.

Простой ответ: Сделайте что-нибудь подобное в заголовочном файле и используйте его везде:

#define NegativeNaN log(-1)

Если вы хотите проделать с ними какие-то манипуляции, лучше напишите какую-нибудь расширенную функцию-оболочку вокруг exp(), например extended_exp() и так далее!

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