在 C++ 中使用 NaN?
Posted
技术标签:
【中文标题】在 C++ 中使用 NaN?【英文标题】:Using NaN in C++? 【发布时间】:2010-09-19 02:54:36 【问题描述】:在 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
是否有一个好的、可移植的替代方案,在使用时会引发浮点异常?
【问题讨论】:
嗯...我正在玩这个,因为我现在很好奇,但我无法让我的提出异常。你做了什么来获得异常? @JeffreyMartinez 这不是一个普通的 C++ 异常,如果你这么想的话。这是一个浮点异常:参见注释here。 【参考方案1】:您可以将信号 NaN 写入变量而不会触发类似这样的异常 (nb: untested)
void set_snan( double &d )
long long *bits = (long long *)&d;
*bits = 0x7ff0000080000001LL;
它适用于大多数地方,但不,它不是 100% 便携的。
【讨论】:
【参考方案2】:您的 C++ 实现可能具有用于访问浮点环境以测试和清除某些浮点异常的 API。请参阅my answer to a related question 了解更多信息。
【讨论】:
【参考方案3】:好吧,看看安静和信号 NaN 的定义,我真的看不出有什么区别。
您可以自己使用这些函数中使用的代码,也许它可以防止异常,但是在这两个函数中没有看到异常,我认为它可能与其他东西有关。
如果你想直接分配NaN:
double value = _Nan._Double;
【讨论】:
【参考方案4】:信号 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;
;
【讨论】:
boost::optional<T>
是一个很好的替代方案,适用于返回值、局部变量和成员。此外,它不调用默认构造函数,并且在大多数情况下使用引用类型。【参考方案5】:
在对此进行了更多研究后,看起来signaling_NaN
提供的信息是无用的。如果启用了浮点异常,则调用它算作处理信号 NaN,因此它会立即引发异常。如果浮点异常被禁用,则处理信号 NaN 会自动将其降级为安静的 NaN,因此signaling_NaN
无论如何都不起作用。
Menkboy's code 有效,但尝试使用信号 NaN 会遇到其他问题:没有可移植的方法来启用或禁用浮点异常(如提到的 here 和 here),如果你依赖启用异常时,第三方代码可能会禁用它们(如here 所述)。
看来Motti's solution确实是最好的选择。
【讨论】:
【参考方案6】:简单的答案: 在头文件中做这样的事情并在其他地方使用它:
#define NegativeNaN log(-1)
如果您希望对它们进行某种操作,最好在 exp()
周围编写一些扩展包装函数,例如 extended_exp()
等等!
【讨论】:
以上是关于在 C++ 中使用 NaN?的主要内容,如果未能解决你的问题,请参考以下文章