你能从C ++的溢出中得到一个“nan”吗?

时间:2012-10-07 12:53:45

标签: c++ debugging nan

我正在编写一个程序,它使用很长的递归(大约50,000)和一些非常大的向量(也是50,000个double类型的长度)来存储每个递归的结果,然后再对它们求平均值。在程序结束时,我希望得到一个数字输出。

然而,我得到的一些结果是“nan”。神秘的是,如果我减少递归次数,程序将正常工作。所以我猜这可能与矢量的大小有关。所以我的问题是,如果你在一个很长的向量(或说数组)中出现溢出,会产生什么影响?你会得到一个像我这样的“南”吗?

关于我的程序的另一个神秘之处在于我尝试了一些更大的递归(100,000),但输出正常。但是当我更改参数值时,存储在向量中的每个数字都会变大(尽管它们仍然是double类型),输出变为“nan”。矢量的最大容量是否取决于它存储的数字的大小?

2 个答案:

答案 0 :(得分:2)

取决于计算的确切性质。如果你只是添加不是 NaN的数字,结果也不应该是NaN。但它可能是+无穷大。

但是, 将获取NaN,例如你的计算的某些部分产生+无穷大,另一个 - 无穷大,你后来添加这两个结果。

假设您的架构符合IEEE 754,这个http://en.wikipedia.org/wiki/NaN#Creation告诉了算术运算返回NaN的情况。

答案 1 :(得分:2)

你没有告诉我们你的递归是什么,但是如果使用平方根,pow,反正弦或反余弦,生成具有长序列操作的NaN是相当容易的。

假设您的计算产生一个数量,称之为x,这应该是某个角度θ的正弦值,并假设基础数学指示x必须始终在-1和1之间, 包括的。您可以通过取x的反正弦来计算θ。

问题在于:在计算机上完成的算术只是实数算术的近似值。 IEEE浮点数的加法和乘法不可传递。对于x而言,您可能得到的值为1.0000000000000002而不是1.取此值的反正弦,您就得到NaN。

标准技巧是防止因数字错误而导致的遗漏。请勿使用内置的asinacossqrtpow。使用包装来保护asin(1.0000000000000002)sqrt(-1e-16)之类的内容。使前pi / 2而不是NaN,并使后者为零。这无疑是一个骗局,这样做会让你陷入困境。如果问题是您的计算结果不正确怎么办?将1.0000000000000002视为1是合法的,但最好不要将值100视为1.将asin包装器的值100最好通过抛出异常而不是截断为1来处理。 / p>

无穷大和NaN还有另一个问题:它们会传播。一次计算中的Inf或NaN很快变成Inf或NaN,数百个,然后是数千个值。我通常会让浮点机器在获得Inf或NaN而不是继续时引发浮点异常。 (注意:浮点异常不是C ++异常。)执行此操作时,除非有适当的信号处理程序,否则程序将会爆炸。这不一定是坏事。您可以在调试器中运行该程序,并准确找到问题出现的位置。没有这些浮点异常,很难找到问题的根源。