!NaN不是NaN吗?

6

我遇到了一段在gcc下会输出警告的代码:

float f;
// Calculate a value for f
if (!f == 0.0)
{
    // Handle it being non-zero
}

很可能只是其他团队成员的笔误,仔细检查代码后,真正意思应该是:
if (f != 0.0)
// OR
if (!(f == 0.0))

我已经更正了代码,但我想知道!NaN会评估为什么。我们在if内部使用f值,所以我们不希望NaN通过检查。


请记住,由于浮点计算的不精确性,f != 0.0可能不足够。您可能需要在其中使用epsilon - user4581301
f在条件语句之前被初始化了吗?你怎么知道f的值是NaN? 你收到了哪些警告? - Some programmer dude
f 应该永远不会是 NaN(除非宇宙射线扭曲了一两个位!)- 这只是为了满足我的好奇心,而不是实际的生产 bug,因此使用了 [tag:language-lawyer] 标签。 - Ken Y-N
@user4581301 实际上,这是一个常量,它从(基本上)一个环境变量初始化,所以有人将其设置为“0.000000000000000000001”不是我的问题!0.0表示未从环境中初始化。 - Ken Y-N
1
足够好。这只是一个一般性的警告,因为在测试时关于我们可以期望在 f 中得到什么信息的唯一给定信息是 // 计算 f 的值,这表明涉及到一些数学。NaN 是一个奇怪的生物,有许多形态。期待看到语言专家对 !NaN 意味着什么做出的回应。 - user4581301
3
“!f” 是一个布尔型变量。 - Sid S
3个回答

3
如果您想避免在if语句中出现NaN,可以使用以下函数进行检查:bool isnan( float arg );。从该函数的参考文献中可以得知:“NaN值永远不等于它们自己或其他NaN值。根据IEEE-754标准,复制NaN不需要保留其位表示(符号和有效数字),但大多数实现会这样做。” 另一种测试浮点值是否为NaN的方法是将其与自身进行比较。
bool is_nan(double x) { return x != x; } 

C++草案(N4713)说明:
8.5.2.1一元运算符 [expr.unary.op] …… 9. 逻辑非运算符!的操作数在上下文中转换为bool(第7条款);如果转换后的操作数为false,则其值为true,否则其值为false。结果的类型为bool。
7.14布尔转换[conv.bool] 1. 算术、未作用域的枚举、指针或指向成员的prvalue可以转换为bool型的prvalue。零值、空指针值或空成员指针值被转换为false;其他任何值都被转换为true。
结论:由于NaN在表达式!NaN中被上下文转换为true,所以!NaNfalse,因此不是NaN

3

请查看https://en.cppreference.com/w/cpp/language/implicit_conversion

整型、浮点型、未作用域枚举类型、指针和成员指针类型的 prvalue 可以转换为 bool 类型的 prvalue。

值为零(对于整型、浮点型和未作用域枚举类型)、空指针和空成员指针值变为 false。所有其他值变为 true。

因此,!f == 0.0 等同于 !(f != 0.0) == 0.0 或者 (f == 0.0) == false 或者 f != 0.0


太好了!但是为了完整回答这个问题,你仍然需要说出当f!=0.0时NaN的值是多少(提示:你引用的最后一段已经回答了这个问题,而不需要重写任何术语 :-))。 - Christophe
我也担心浮点异常,因为我认为gcc默认开启了它们。!NaN会引发浮点异常吗?我还发现这个有用的参考资料 - Ken Y-N
@Christophe,你真的认为需要明确说明非零值与零进行比较会返回false吗? - Alan Birtles
1
@KenY-N 我认为无论使用哪种表达式,行为都是相同的,如果 NaN != 0 抛出异常,那么 !NaN 也会抛出异常。 - Alan Birtles
@AlanBirtles -- 你说得对,这不仅是维基百科上的说法。这就是IEEE-754的规定。!=用于无序比较时返回true。抱歉,评论已删除。 - Pete Becker
显示剩余2条评论

0

只需简单地使用

if (!isnan(f)&& !f == 0.0)
    {
        cout<<"Filtered NaN values"<<endl;

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接