2008-10-24 8 views
31

Каков наилучший способ использования NaNs в 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, которая будет поднимать исключение с плавающей запятой при использовании?

+0

Хмм ... Я играю с этим, потому что мне сейчас любопытно, но я не мог заставить мое возбуждать исключение. Что вы сделали, чтобы получить исключение? – 2008-10-25 00:08:52

+0

@JeffreyMartinez Это не нормальное исключение C++, если это то, о чем вы думаете. Это исключение с плавающей запятой: см. Примечания [здесь] (http://en.cppreference.com/w/cpp/numeric/fenv). – bames53 2012-11-05 15:55:23

ответ

11

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

Menkboy's code работает, но при попытке использовать сигнализацию пренебрежимо малых наталкивается на другие проблемы: нет переносимого способа включить или отключить плавающей исключения точки (как упомянуто here и here), и если вы полагаетесь на исключениях быть включен, треть код участника может отключить их (как описано here).

Похоже, что Motti's solution действительно лучший выбор.

3

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

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

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

0

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

3

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

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

Если вы хотите, чтобы непосредственно присвоить NaN:

double value = _Nan._Double; 
9

Что сигнализации 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; 
    } 
}; 
3

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

#define NegativeNaN log(-1) 

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