在 C++ 中使用 NaN?

发布于 2024-07-07 12:01:32 字数 459 浏览 8 评论 0原文

在 C++ 中使用 NaN 的最佳方法是什么?

我找到了 std::numeric_limits::quiet_NaN()std::numeric_limits::signaling_NaN()。 我想使用 signaling_NaN 来表示未初始化的变量,如下所示:

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

但是,这会在赋值时发出信号(引发异常)。 我希望它在使用时引发异常,而不是在分配时引发异常。

有没有办法使用signaling_NaN而不引发赋值异常? 是否有一个好的、可移植的信号替代方案来替代signaling_NaN,在使用时会引发浮点异常?

What's the best way to use NaNs in C++?

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:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

哆啦不做梦 2024-07-14 12:01:32

经过更多研究后,看起来 signaling_NaN 所提供的毫无用处。 如果启用了浮点异常,则调用它会被视为处理信号 NaN,因此它会立即引发异常。 如果禁用浮点异常,则处理信号 NaN 会自动将其降级为安静 NaN,因此 signaling_NaN 无论如何都不起作用。

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

所以看起来 Motti 的解决方案确实是最好的选择。

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.

Menkboy's code works, 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 here and here), and if you're relying on exceptions being enabled, third party code may disable them (as described here).

So it seems like Motti's solution is really the best choice.

早乙女 2024-07-14 12:01:32

发信号 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; 
   }
};

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:

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; 
   }
};
So尛奶瓶 2024-07-14 12:01:32

您可以将信号 NaN 写入变量,而不会触发异常,如下所示(注意:未经测试)

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

它可以在大多数地方工作,但不,它不是 100% 可移植的。

You can write a signalling NaN into a variable without triggering an exception with something like this (nb: untested)

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.

薄荷港 2024-07-14 12:01:32

好吧,看看安静和信号 NaN 的定义,我真的看不出有什么区别。

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

如果你想直接赋值 NaN:

double value = _Nan._Double;

Well, looking after the definition of both quiet and signaling NaN, I can't really make out any difference.

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:

double value = _Nan._Double;
三寸金莲 2024-07-14 12:01:32

简单回答:
在头文件中执行类似的操作并在其他地方使用它:

#define NegativeNaN log(-1)

如果您希望对它们进行某种操作,最好在 exp() 周围编写一些扩展包装函数,例如 extended_exp()< /代码>等等!

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!

╰つ倒转 2024-07-14 12:01:32

您的 C++ 实现可能具有用于访问浮点环境的 API,以测试和清除某些浮点异常。 有关详细信息,请参阅我对相关问题的回答

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 question for more information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文