在什么情况下我们会在 C++ 中得到 nan?

问题描述

我阅读了一些关于 nan文章,但网站并未提及所有情况。例如我编译了这段代码并收到了nan。 为什么不给 inf

#include <iostream>

using namespace std;

int main()
{
    double input,counter,pow= 1,sum = 0,sign = 1.0;
   
    cin >> input;
    
    for (counter = 1; pow / counter >= 1e-4; counter++)
    {
        pow *= input;
        sum += sign * pow / counter;
        sign = -sign;
    }
    cout << sum << endl;
}

结果是:

nan

解决方法

输入“2”时,您的程序将两个符号相反的无穷大相加,从而生成 NaN。这是因为反复将 pow 乘以 2 导致它变成无穷大,而交替的 sign 导致正无穷大被添加到 sum 中来自前一次迭代的负无穷大,反之亦然反之。

然而,不清楚为什么您会看到任何输出,因为一旦计数器达到 253(在典型的 C++ 实现中)counter++ 变得无效,因为 double 格式缺乏表示 253+1 的精度,因此将 253 加一的结果四舍五入为 253。所以 counter 停止改变,循环永远持续下去。

一种可能性是您的编译器生成的代码总是会终止循环,因为 C++ 标准的“前进”条款(草案 n4659 中的 4.7.2)允许这样做。它说编译器可以假设你的循环不会永远继续而不做一些有用的事情(比如写输出或调用 exit),这允许编译器生成退出循环的代码,即使它会永远继续输入的“2”。

根据 IEEE-754 标准,产生 NaN 结果的操作包括:

  • 对 NaN 的操作,
  • 零乘以无穷大,
  • 两个同号无穷大相减或两个异号无穷大相加,
  • 零除以零或无穷除以无穷,
  • 除数为零或被除数为无穷大时的余数,
  • 小于零的值的平方根,
  • 某些实用程序和数学例程中的各种异常(例如 pow,请参阅 IEEE-754 9.2、5.3.2 和 5.3.3)。

C++ 实现并不总是符合 IEEE-754,但这些通常是 NaN 来源的良好指南。