如何处理溢出和下溢?

kev*_*112 4 math matlab computer-science rounding

我是Matlab的新手并试图找出当答案实际上在范围内时如何处理溢出和下溢算法.

例如:

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

任何帮助表示赞赏.

Spe*_*tre 7

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

这背后的主要问题是首先检测溢出/下溢

这是有时很难,因为他们也出现在其他情况下,当计算不返回zeroinf.例如,在数值积分期间,溢出/下溢可能导致结果错误但仍然是非零数字.

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

??????????.????FFFFFFFFFFF?? hex
Run Code Online (Sandbox Code Playgroud)

当您查看小数部分并检测到许多FFFFF数字位于最低位数附近时,您的数字很可能是下溢或非常接近该点.每次迭代饱和时,零或者最后的数量通常会减少:

??????????.????FFFFFFFFFFF hex
Run Code Online (Sandbox Code Playgroud)

溢出类似地饱和,但在另一边像这样:

FFFFFFFFFFF.FFFFFF?????? hex
Run Code Online (Sandbox Code Playgroud)

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

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

检测上溢/下溢的另一种方法是预测结果数量级.例如

  • * 将指数汇总在一起
  • / 减去指数
  • sqrt 将指数减半
  • +,-可以导致+1/-1更大的指数

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

最重要的是,当结果精度不适合尾数时,可能会发生下溢.因此,您需要注意增加结果使用位的操作,如:

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

+,-操作是最糟糕的,例如,如果你加2^100 + 2^-100那么结果需要尾数的200位,而操作数本身具有尾数的展台只有1位.

如果检测到溢出/下溢怎么办:

  1. 改变方程

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

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

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

  3. 停止迭代

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

    1/1! + 1/2! + 1/3! + ... + 1/n!
    
    Run Code Online (Sandbox Code Playgroud)

    在某些情况下,如果您在停止迭代时检测到遇到溢出/下溢的子结果,则仍然具有相对准确的计算结果.不要忘记不要将溢出的子结果包含在最终结果中.

  • 非常好的答案(和+1缺乏广泛的子弹:).只是一个matlab注释:matlab默认使用双打,但是有一个符号数学工具箱,允许使用命令[`vpa`]进行变量精度算术(http://www.mathworks.com/help/symbolic/vpa. html)(@LuisMendo)在他的评论中提到了.这样就可以准确地表示`x = vpa('2e160')`,但请注意,这不等于`x = vpa(2e160)`,后者已经表示为双精度(失去精度). (2认同)