简体   繁体   English

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

[英]When does NaN not propagate in C++?

NaN propagates through "most" operations as described in NaN - Wikipedia . NaN 通过“大多数”操作传播,如NaN - Wikipedia中所述。

I would like to know the operations which NaN does NOT propagate.我想知道 NaN 不传播的操作。 For example, I'm coding in C++ and found that following code prints 1 , which is not NaN.例如,我用 C++ 编写代码,发现以下代码打印1 ,这不是 NaN。

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

For std::pow function, this behavior is described in std::pow - cppreference.com .对于std::pow函数,此行为在std::pow - cppreference.com中进行了描述。

Could you share any other examples?你能分享任何其他例子吗?

std::pow is not really an operator in the sense that something like the multiplication in a * b is an operation. std::pow并不是真正的运算符,因为a * b中的乘法是一种运算。 It's a function .这是一个功能 And functions can have branches which can deal with a NaN as they please.函数可以有分支,可以随意处理NaN Another similar std function is, in a sense, std::is_nan .从某种意义上说,另一个类似的std函数是std::is_nan This doesn't propagate NaN either: it returns a bool which is implicitly convertible to a numeric type:这也不会传播NaN :它返回一个可以隐式转换为数字类型的bool

std::is_nan(std::is_nan(a))

is false for any type a that allows the expression to compile.对于任何允许表达式编译的类型a都是false的。 Other examples include std::fpclassify and std::isfinite .其他示例包括std::fpclassifystd::isfinite I particularly like std::fpclassify as an example since it has an int return type, so really it's no less of a numeric function than pow !我特别喜欢std::fpclassify作为示例,因为它具有int返回类型,所以它实际上不亚于pow的数字函数!

Note that the implicit conversion of NaN to bool is defined to be请注意, NaNbool的隐式转换定义为false true according to the accepted answer to this question , which is important.根据这个问题的公认答案是true ,这很重要。 It allows !它允许! , && , and || , &&|| to work with an NaN .使用NaN Finally, the expression separator operator , doesn't propagate NaN either, and an NaN on the unused branch of a ternary conditional operation is ignored.最后,表达式分隔符运算符,也不会传播NaN ,三元条件运算的未使用分支上的NaN将被忽略。

The other case I would try is pow(0, NaN) .我会尝试的另一种情况是pow(0, NaN) If one has pow(0,0) == 1 then one should expect如果一个人有pow(0,0) == 1那么一个人应该期待

 pow(0, NaN) == 1

There is a rationale for this, and actually it is needed for consistent behavior.这是有原因的,实际上它是一致行为所必需的。 Even though there is no IEEE standard dictating the behavior of all elementary functions with respect to NaN, there is a very basic rule:尽管没有 IEEE 标准规定所有初等函数相对于 NaN 的行为,但有一个非常基本的规则:

If for all finite point numbers x including +inf and -inf (but excluding NaN) we have如果对于所有有限点数x ,包括 +inf 和 -inf(但不包括 NaN)我们有

f(const1, x) == const2

then (and only then) one also must return a non-NaN result然后(并且只有那时)一个人也必须返回一个非 NaN 结果

f(const1, NaN) == const2

#Long explanation #详细解释

This is because NaN represents "undefined" or "any other numeric value from -inf.. inf".这是因为 NaN 表示“未定义”或“来自 -inf.. inf 的任何其他数值”。 Why?为什么? Consider the prototypical example 0/0.考虑原型示例 0/0。 If one has the equation如果有人有等式

 b = a * x

and wants to solve for x .并想解决x Clearly the solution is显然解决方案是

x = b/a

Now if a == b == 0 then the original equation has infinitely many solutions, namely all finite numbers x .现在如果a == b == 0那么原方程有无限多个解,即所有有限数x That's why NaN means "unspecified" and 0/0 == NaN .这就是为什么 NaN 表示“未指定”和0/0 == NaN Now if an unspecified number (ie NaN) enters a function as an argument, it most often will cause an "unspecified" answer.现在,如果一个未指定的数字(即 NaN)作为参数进入一个函数,它通常会导致一个“未指定”的答案。 The exception is where the output does not depend on the input, and in this case one should/must not return NaN.例外情况是输出不依赖于输入,在这种情况下应该/不得返回 NaN。

Consider考虑

pow(1, a/b)

This expression always evaluates to 1 for nonzero a and b , which makes sense from a mathematical point of view as the 1^x in a mathematical sense does not depend on x .对于非零ab ,此表达式的计算结果始终为 1,这从数学的角度来看是有意义的,因为数学意义上的1^x不依赖于x So also numerically one would require that for a = 0 or b = 0 (and hence x=NaN ) one also obtains 1.因此,从数值上讲,对于a = 0b = 0 (因此x=NaN ),人们也需要获得 1。

So if one agrees upon the fact that所以如果一个人同意这样一个事实

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

then one also has to define那么还必须定义

pow(1,NaN) = 1

for consistent behavior.一致的行为。 The same applies to pow(0,c) but also evaluation of a polynomial of degree zero should generate a non-NaN output on NaN input.这同样适用于pow(0,c)但零阶多项式的计算也应在 NaN 输入上生成非 NaN 输出。

Note: this reasoning can be applied to any function, including the built-in operators.注意:这个推理可以应用于任何函数,包括内置运算符。

Here's an example demonstrating functions of NaN which return non-NaN.下面是一个示例,演示返回非 NaN 的 NaN 函数。 The list is in IEEE 754-2008, 9.2.1 Special values (there are some others functions, but they don't seem to be implemented in C++):该列表在 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';
}

The output is:输出是:

inf
inf
1
1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM