【问题标题】:Is !NaN not a NaN?!NaN 不是 NaN 吗?
【发布时间】:2019-03-26 04:11:12
【问题描述】:

我遇到了这段代码,它用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 值,因此我们不希望NaNs 通过检查。

【问题讨论】:

  • 请记住,由于浮点计算的不精确性,f != 0.0 可能还不够。你很可能会在那里need an epsilon
  • f 是否在条件之前被初始化?是什么让您认为 f 的值是 NaN?你会收到什么警告?
  • f 永远不应该是 NaN(除非宇宙射线旋转一两点!) - 这是为了我自己的求知欲,而不是真正的活虫,因此 language-lawyer 标签.
  • 足够好。这只是一个一般性警告,因为在测试时我们可以在f 中预期的唯一信息// Calculate a value for f 表明涉及一些数学。 NaN 是一种具有多种形状的奇怪野兽。期待看到语言律师在回应!NaN 的含义时会提出什么(如果有的话)。
  • !fbool

标签: c++ floating-point language-lawyer nan


【解决方案1】:

如果你想避免 if 内部出现 NaN,可以使用函数

bool isnan( float arg );

进行检查。

来自函数的reference

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. 算术、无作用域枚举、指针或指向成员的指针类型的纯右值可以转换为 bool 类型的纯右值。将零值、空指针值或空成员指针值转换为 false; 任何其他值都将转换为 true。

结论:由于 NaN 在表达式!NaN 中被上下文转换为true,所以!NaNfalse,因此不是NaN。。 p>

【讨论】:

    【解决方案2】:

    简单地使用

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

    【讨论】:

      【解决方案3】:

      https://en.cppreference.com/w/cpp/language/implicit_conversion

      整数、浮点、无范围枚举、指针和指向成员的指针类型的纯右值可以转换为布尔类型的纯右值。

      值零(对于整数、浮点和无范围枚举)以及空指针和指向成员的空指针值变为假。所有其他值都变为 true

      因此!f == 0.0 等价于!(f != 0.0) == 0.0(f == 0.0) == falsef != 0.0

      【讨论】:

      • 太棒了!但是要完全回答这个问题,您仍然必须说出 f!=0.0 对于 NaN 的含义(提示:您的引文的最后一段回答了这个问题而没有重写任何术语 :-))
      • 我也担心floating-point exceptions 因为gcc 默认情况下会启用它们,我想。 !NaN 会引发浮点异常吗?我还发现了这个a useful reference
      • @Christophe 你真的认为有必要明确声明与零相比的非零值返回假吗?
      • @KenY-N 我认为这两个表达式的行为都是一样的,如果NaN != 0 抛出异常,那么!NaN 也会抛出异常。
      • @KenY-N Linux/x86-64 上的 GCC 默认不会引发产生或涉及 NaN 的算术运算异常,甚至不会引发信号 NaN。我不知道Windows。 (顺便说一句,唯一不安静的 NaN 是通过调用 std::numeric_limits&lt;double&gt;::signaling_NaN() 显式生成的。)如果出于任何原因,您确实需要异常信号 NaN,请调用 feenableexcept(FE_INVALID) as explained here。跨度>
      猜你喜欢
      • 2011-04-05
      • 2011-10-22
      • 2014-05-01
      • 2013-12-17
      • 1970-01-01
      • 2019-04-12
      • 2016-03-19
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多