NaN何时不在C ++中传播?

时间:2018-03-02 10:30:54

标签: c++ nan

NaN传播通过"大多数" NaN - Wikipedia中描述的操作。

我想知道NaN不传播的操作。例如,我在C ++中进行编码,发现以下代码打印的是1,而不是NaN。

const double result = std::pow(1, std::numeric_limits<double>::quiet_NaN());
std::cout << result << std::endl;

对于std::pow函数,std::pow - cppreference.com中描述了此行为。

你可以分享其他任何例子吗?

3 个答案:

答案 0 :(得分:6)

std::pow在某种意义上并不是真正的运算符,因为a * b中的乘法就像是一个操作。它是功能。函数可以有分支,可以随意处理NaN。在某种意义上,另一个类似的std函数是std::is_nan。这也不会传播NaN:它返回一个bool,它可以隐式转换为数字类型:

std::is_nan(std::is_nan(a))
对于允许表达式编译的任何类型false

a。其他示例包括std::fpclassifystd::isfinite。我特别喜欢std::fpclassify作为示例,因为它具有int返回类型,所以它实际上不仅仅是pow的数字函数!

请注意,NaNbool的隐式转换根据{{3}的接受答案定义为 false true这很重要。它允许!&&||NaN一起使用。最后,表达式分隔符运算符 ,也不会传播NaN,并且忽略三元条件运算的未使用分支上的NaN

答案 1 :(得分:3)

我会尝试的另一种情况是pow(0, NaN)。如果有pow(0,0) == 1,那么应该期待

 pow(0, NaN) == 1

这有一个理由,实际上它需要一致的行为。 即使没有IEEE标准规定基本功能相对于NaN的行为,也有一个非常基本的规则:

如果所有有限点数x包括+ inf和-inf(但不包括NaN)我们有

f(const1, x) == const2

然后(并且只有那时)还必须返回非NaN结果

f(const1, NaN) == const2

长解释

这是因为NaN表示“未定义”或“来自-inf .. inf的任何其他数值”。为什么?考虑原型示例0/0。 如果有一个等式

 b = a * x

并希望解决x。显然,解决方案是

x = b/a

现在如果a == b == 0那么原始方程有无限多个解,即所有有限数x。这就是NaN意味着“未指定”和0/0 == NaN的原因。现在,如果未指定的数字(即NaN)作为参数输入函数,则通常会导致“未指定”的答案。例外情况是输出不依赖于输入,在这种情况下,应该/不得返回NaN。

考虑

pow(1, a/b)

对于非零ab,此表达式的计算结果始终为1,从数学角度来看这是有道理的,因为数学意义上的1^x不依赖于{{1} }}。所以在数字上也会要求xa = 0(因而b = 0)也会得到1。

所以,如果有人同意这个事实

x=NaN

然后还必须定义

pow(1,-inf) = pow(1,inf) = 1 

表示一致的行为。这同样适用于pow(1,NaN) = 1 ,但是对零度多项式的求值也应该在NaN输入上生成非NaN输出。

注意:此推理可应用于任何功能,包括内置运算符。

答案 2 :(得分:3)

这是一个证明NaN返回非NaN功能的例子。该列表在IEEE 754-2008中, 9.2.1特殊值(还有一些其他功能,但它们似乎没有在C ++中实现):

#include <cmath>
#include <limits>
#include <iostream>

int main()
{
    const auto nan=std::numeric_limits<double>::quiet_NaN();
    const auto inf=std::numeric_limits<double>::infinity();
    std::cout << std::hypot(nan,inf) << '\n';
    std::cout << std::hypot(inf,nan) << '\n';
    std::cout << std::pow(nan, 0) << '\n';
    std::cout << std::pow(1,nan) << '\n';
}

输出结果为:

inf
inf
1
1