English 中文(简体)
在C++中使用NaN?
原标题:
  • 时间:2008-10-24 21:56:22
  •  标签:

如何在C++中使用NaN最佳方法?

我发现了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 ,在使用时会引发浮点异常?

最佳回答

经过进一步的调查,看起来signaling_NaN是没有用的。如果启用了浮点异常,那么调用它会计数为处理一个信号NaN,因此它会立即引发异常。如果禁用浮点异常,那么处理一个信号NaN会自动降级为安静NaN,因此无论如何signaling_NaN都无法工作。

Menkboy的代码可行,但尝试使用信号NaN会遇到其他问题:没有可移植的方法来启用或禁用浮点异常(如此处此处所示),如果您依赖于启用异常,第三方代码可能会禁用它们(如此处所述)。

所以似乎Motti的解决方案是最好的选择。

问题回答

什么是信令 NAN 意味着当 CPU 遇到它时就会发出信号(因此得名)。如果您想检测未初始化的变量,那么通常通过升高编译器的警告级别来检测使用未初始化值的所有路径。如果失败,您可以使用一个包装类来存储一个布尔值表示该值是否已初始化:

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; 
   }
};

你可以像这样写一个信号NaN值到一个变量中,而不会触发异常(注:未经测试)。

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

它可以在大多数地方使用,但不,它不是100%便携的。

嗯,关注静默和信号 NaN 的定义,我实际上不能分辨出任何差别。

你可以自己使用这些函数中使用的代码,也许这样可以防止异常,但是在这两个函数中没有看到异常,我认为可能与其他事情有关。

如果您想直接指定NaN:

double value = _Nan._Double;

Simple answer: Do something like this in the header file and use it everywhere else:

#define NegativeNaN log(-1)

如果您希望对它们进行某种操纵,则最好编写一个扩展的包装器函数,例如extended_exp()等!

您的C ++实现可能具有访问浮点环境以测试和清除某些浮点异常的API。有关更多信息,请参见我的一篇相关问题的答案





相关问题
热门标签