如何处理上溢和下溢?

How to deal with overflow and underflow?

我是 Matlab 的新手,想弄清楚当答案实际上在范围内时如何处理上溢和下溢算法。

例如:

x = 2e+160
x = x*x (which returns inf, an overflow)
x = sqrt(x) (which is in the range)

感谢任何帮助。

我不是 Matlab 用户,所以请记住这一点。

这背后的主要问题是先检测overflow/underflows

这有时很难,因为它们也会出现在计算不 return zeroinf 的其他情况下。例如在数值积分期间 overflow/underflows 可能导致结果错误但仍然是一个非零数。

根据我的经验,我倾向于认为以十六进制表示形式查看数字是有用的(除非您的 HW/SW 计算在内部对变量使用十进制基数,这很少见,因为大多数 HW/SW 是二进制的) .因此,请查看十六进制形式的数字并检测如下模式:

??????????.????FFFFFFFFFFF?? hex

当您查看小数部分并检测到许多 FFFFF 出现在最低位附近时,那么您的数字 很可能 下溢或非常接近那一点。零的数量或最后的数量通常随着每次迭代饱和而减少:

??????????.????FFFFFFFFFFF hex

溢出同样饱和,但在另一边是这样的:

FFFFFFFFFFF.FFFFFF?????? hex

对于某些算法来说,在下一次迭代之前舍入 up/down 这样的数字会更精确,但是在应用于未知数之前,您需要始终检查一些众所周知的计算示例是否属于这种情况……看这里:

  • floating point divider

这是使用这种技术的一个很好的算法示例

检测overflow/underflows的另一种方法是预测结果数量级。例如

  • * 对指数求和
  • / 减去指数
  • sqrt 指数减半
  • +,- 可以得到较大指数
  • +1/-1

因此,如果您正在处理 big/small 指数,您就会知道哪些操作可能会导致溢出问题。

除此之外,当您的结果精度不适合尾数时,可能会发生下溢。所以你需要小心增加结果的使用位的操作,如:

  • a*b ab
  • 中使用的位总和
  • +,- (a,b) 的最大使用位 - (a,b) 的最小使用位
  • / 添加一些位来保存分数 ...

+,- 运算是最糟糕的,例如,如果您添加 2^100 + 2^-100,则结果需要 200 位尾数,而操作数本身只有 1 位尾数。

检测到overflow/underflow怎么办:

  1. 改变等式

    如前所述,您可以切换到 log,它可以轻松处理更大的范围,但还有其他问题。通常算法的微小变化也会导致结果按不同的因素缩放,但子结果仍在安全范围内,因此您只需要最终结果即可缩小到危险范围。在更改方程式时,您应该始终考虑结果的精确性和有效性。

  2. 使用更大的变量数据类型

    如果我没记错的话,Matlab 有任意精度的数字,所以如果需要的话可以使用它们。您还可以使用标准 float/double 变量并将值存储到更多变量中,如下所示:

  3. 停止迭代

    例如,一些算法使用如下系列:

    1/1! + 1/2! + 1/3! + ... + 1/n!
    

    在某些情况下,如果您检测到在停止迭代时命中了 overflowing/underflowing 子结果,您仍然可以获得相对准确的计算结果。不要忘记不要将溢出的子结果包含到最终结果中。