在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一样无用。如果启用了浮点异常,则调用它将计为处理信令NaN,因此它会立即引发异常。如果禁用浮点异常,则处理信令NaN会自动将其降级为安静的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写入变量,而不会触发此类异常(nb:untested)

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

它适用于大多数地方,但不是,它不是100%便携式。

那么,看看安静和信号NaN的定义,我真的无法发现任何差异。

您可以自己使用这些函数中使用的代码,也许它会以某种方式阻止异常,但在这两个函数中看不到异常,我认为它可能与其他函数有关。

如果您想直接指定NaN:

double value = _Nan._Double;

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

#define NegativeNaN log(-1)

如果你想对它们进行某种操作,最好在exp()之类的extended_exp()中编写一些扩展的包装函数,等等!

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top