2

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

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

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

4

2 回答 2

3

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

假设您的计算产生了一个量,称为它x,它应该是某个角度 θ 的正弦值,并假设基础数学规定它x必须始终介于 -1 和 1 之间(含)。您通过取 的反正弦来计算 θ x

这就是问题所在:在计算机上完成的算术只是对实数算术的近似。IEEE 浮点数的加法和乘法是不可传递的。你很可能得到一个 1.0000000000000002x而不是 1 的值。取这个值的反正弦,你得到一个 NaN。

一个标准的技巧是防止那些因数值错误而导致的未遂事件。不要使用内置的asin, acos,sqrtpow. 使用可以防止诸如asin(1.0000000000000002)和之类的包装器sqrt(-1e-16)。将前者设为 pi/2 而不是 NaN,并将后者设为零。诚然,这是一个杂牌,这样做会给你带来麻烦。如果问题是您的计算公式不正确怎么办?将 1.0000000000000002 视为 1 是合法的,但最好不要将值 100 视为 1。asin包装器的值 100 最好通过抛出异常而不是截断为 1 来处理。

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

于 2012-10-07T14:07:14.110 回答
2

取决于您的计算的确切性质。如果您只是将不是NaN 的数字相加,那么结果也不应该是 NaN。不过,它可能是+无穷大。

但是,如果您的计算的某些部分产生 +infinity,另一个 -infinity,并且您稍后将这两个结果相加,您将得到 NaN。

假设您的体系结构符合 IEEE 754,此http://en.wikipedia.org/wiki/NaN#Creation说明算术运算返回 NaN 的情况。

于 2012-10-07T12:59:55.537 回答