C ++如何处理NAN?有标准方式还是编译器依赖?

时间:2014-07-29 11:14:11

标签: c++ floating-point nan

在需要处理sin(x)/ x函数的程序中,我遇到了NAN问题,我在以下代码中简化了问题:

#include <iostream>
#include <cmath>

int main()
{
    std::cout.precision(15);

    //This line compiles and run in g++, but does not compile in Visual Studio 2013
    std::cout << 0.0/0.0 << std::endl;

    //This line compiles and run in both g++ and VS2013
    std::cout << std::sin(0.0)/0.0 << std::endl;

    return 0;
}

在g ++中,输出为:-nan -nan,在VS2013中,输出为:-1.IND,因为第一行没有编译所以我将其注释掉了。

我的问题是:

  1. 这个'-1.IND'是什么意思?

  2. 似乎NAN处理依赖于编译器,这应该在C ++中标准化吗?为什么呢?

  3. 我用这个黑客来处理这个问题:

    double sinc(double x)
    {
        if(x == 0.0)
            return 1.0;
        return std::sin(x)/x;
    }
    
  4. 这是正确的方法吗?

    编辑:另一个问题,4。为什么VS2013处理0.0 / 0.0和sin(0.0)/0.0不同?

5 个答案:

答案 0 :(得分:12)

你的回答也有类似的问题:

  

1.这是什么&#39; -1.IND&#39;意思?

请参阅What do 1.#INF00, -1.#IND00 and -1.#IND mean?

  

2.似乎NAN处理依赖于编译器,这应该在C ++中标准化吗?为什么呢?

请参阅A few things about division by zero in C(它说的是C,但它谈到的是C ++)

  

3.我用这个黑客来处理这个问题:

double sinc(double x) {

    if(x == 0.0)
        return 1.0;
    return std::sin(x)/x; 
}
     

这是正确的方法吗?

是的,sinc函数的这种实现将起作用(感谢@MSalters的评论)在数学上是正确的;但是,请记住,虽然它适用于此案例,但不要养成将double类型与==进行比较的习惯。

答案 1 :(得分:5)

要为(4)添加答案,sin(x)是运行时函数,因此sin(0.0)/0.0作为在运行时计算的表达式处理。 OTOH,0.0/0.0由编译器完全处理,这就是它发现问题的原因。 Visual Studio版本的实现细节,而不是可以计算的内容。

答案 2 :(得分:3)

在C和C ++标准中,完全符合IEEE浮点标准是可选。这是因为,由于我从未清楚过的原因,CPU设计人员讨厌 IEEE浮点标准。我不知道任何 CPU正确有效地实现了整个规范。 (据我所知,你可以拥有的最好的CPU是一个对正常有限数字来说快速且正确的CPU,但如果你想使用非正规数,无穷大和NaN,它会遭受多次数量级的减速。)

C和C ++标准由编译人员编写。编译人员希望能够生成在真实CPU上快速运行的机器代码,并且他们知道真正的CPU会在IEEE浮点上偷工减料,因此他们不能将完整的IEEE浮点符合性作为语言要求。

答案 3 :(得分:2)

  1. 表达式double res = 0.0 / 0.0的编译失败,因为编译器试图优化它确定的代码&#34;无效&#34;表达。它无法优化sin(x) / 0.0之类的表达,因为它无法简化和优化&#34;像这样的代码&#34;。
  2. 显示double数据类型的特殊值取决于平台。但表示依赖于架构。要检查这一点,您可以在不同的体系结构上运行此功能: template<typename T> void inspect(T v1, T v2) { T i_val = v1; i_val /= v2; size_t len = sizeof(T); int* bit_repr = (int*)(&i_val); for (int i = 0; i < (len / sizeof(int)); i ++) { std::bitset<sizeof(int) * 8> bs(*(bit_repr + i)); std::cout << bs; } std::cout << std::endl; }
  3. 使用以下参数调用上一个函数:

    inspect<double>(0.0, 0.0);
    inspect<double>(1.0, 0.0);
    inspect<double>(-1.0, 0.0);
    

答案 4 :(得分:1)

这可能会有所帮助: C ++ 11(所以VS2013)有一些功能可以理解给定的数字是NAN还是有限的。 使用std :: isnan()或std :: isfinite()