在 C++ 中使用 NaN?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/235386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using NaN in C++?
提问by Josh Kelley
What's the best way to use NaNs in C++?
在 C++ 中使用 NaN 的最佳方法是什么?
I found std::numeric_limits<double>::quiet_NaN()
and std::numeric_limits<double>::signaling_NaN()
. I'd like to use signaling_NaN
to represent an uninitialized variable as follows:
我发现std::numeric_limits<double>::quiet_NaN()
和std::numeric_limits<double>::signaling_NaN()
。我想signaling_NaN
用来表示一个未初始化的变量,如下所示:
double diameter = std::numeric_limits<double>::signaling_NaN();
This, however, signals (raises an exception) on assignment. I want it to raise an exception on use, not on assignment.
然而,这在分配时发出信号(引发异常)。我希望它在使用时引发异常,而不是在分配时引发异常。
Is there any way to use signaling_NaN
without raising an exception on assignment? Is there a good, portable alternative to signaling_NaN
that will raise a floating point exception when used?
有什么方法可以在signaling_NaN
不引发赋值异常的情况下使用吗?有没有一个好的、可移植的替代方法signaling_NaN
,在使用时会引发浮点异常?
采纳答案by Josh Kelley
After looking into this some more, it looks like signaling_NaN
is useless as provided. If floating point exceptions are enabled, then calling it counts as processing a signaling NaN, so it immediately raises an exception. If floating point exceptions are disabled, then processing a signaling NaN automatically demotes it to a quiet NaN, so signaling_NaN
doesn't work either way.
在进一步研究之后,它看起来像signaling_NaN
提供的那样没用。如果启用了浮点异常,则调用它算作处理信号 NaN,因此它会立即引发异常。如果禁用浮点异常,则处理信号 NaN 会自动将其降级为安静的 NaN,因此signaling_NaN
无论哪种方式都不起作用。
Menkboy's codeworks, but trying to use signaling NaNs runs into other problems: there's no portable way to enable or disable floating point exceptions (as alluded to hereand here), and if you're relying on exceptions being enabled, third party code may disable them (as described here).
Menkboy 的代码有效,但尝试使用信号 NaN 会遇到其他问题:没有可移植的方法来启用或禁用浮点异常(如此处和此处所提到的),并且如果您依赖于启用的异常,则第三方代码可能禁用它们(如描述在这里)。
So it seems like Motti's solutionis really the best choice.
所以看起来Motti的解决方案真的是最好的选择。
回答by Motti
What signaling NAN means is that when the CPU encounters it a signal is fired, (hence the name). If you want to detect uninitialized variables then raising the warning level on your compiler usually detects all paths that use uninitalized values. Failing that you can use a wrapper class that stores a boolean saying if the value is initialized:
信号 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;
}
};
回答by HS.
Well, looking after the definition of both quiet and signaling NaN, I can't really make out any difference.
好吧,根据安静和信号 NaN 的定义,我真的看不出有什么区别。
You could use the code that is used in those functions yourself, maybe it prevents an exception that way, but seeing no exception in those two functions, I think it might be related to something else.
您可以自己使用这些函数中使用的代码,也许它可以防止异常,但是在这两个函数中没有看到异常,我认为它可能与其他东西有关。
If you want to directly assign the NaN:
如果要直接分配 NaN:
double value = _Nan._Double;
回答by Menkboy
You can write a signalling NaN into a variable without triggering an exception with something like this (nb: untested)
您可以将信号 NaN 写入变量而不会触发类似这样的异常(注意:未经测试)
void set_snan( double &d )
{
long long *bits = (long long *)&d;
*bits = 0x7ff0000080000001LL;
}
It'll work most places, but no, it's not 100% portable.
它可以在大多数地方工作,但不,它不是 100% 便携的。
回答by Rahul
Simple answer: Do something like this in the header file and use it everywhere else:
简单的回答:在头文件中做这样的事情并在其他地方使用它:
#define NegativeNaN log(-1)
If you wish to do some kind of manipulations on them better write some extended wrapper function around exp()
like extended_exp()
and so on!
如果您希望对它们进行某种操作,最好编写一些扩展的包装函数,exp()
诸如此类extended_exp()
!
回答by jwfearn
Your C++ implementation may have an API for accessing the floating point environment to test for and clear certain floating point exceptions. See my answer to a related questionfor more information.
您的 C++ 实现可能具有用于访问浮点环境以测试和清除某些浮点异常的 API。有关更多信息,请参阅我对相关问题的回答。