消除矩阵的舍入误差

时间:2012-12-05 14:16:14

标签: algorithm rounding linear-equation

我的问题是我有一个矩阵,其中所有行的总和,以及所有列的总和为零。所有数字都四舍五入为x小数。

然后我将整个矩阵乘以0到1之间的数字(例如1/6)并将所有数字四舍五入为x小数。现在我无法确定行和列的总和是否为零。 我希望在最小可能调整(或至少非常小的调整)的情况下,总和再次为零

是否存在可以解决此类问题的算法?

示例(非常简单): 矩阵:

    200  -200  0

    400  400  -800

   -600 -200  800

round2((1/6)*矩阵)

33.33  -33.33  0   

66.67  66.67   -133.33

-100   -33.33  133.33

4 个答案:

答案 0 :(得分:2)

您在这里遇到的内容实质上是精确错误。除非你根本没有圆,否则你无能为力。这类似于将照片保存为256色图像。你丢失了信息(基本上是精确的;由于离散化),你无能为力。对于图片,有一些算法可以使图像看起来更平滑/更接近原始图像(例如抖动),但是对于单值数字,您没有这样的东西。

可能的解决方案(实际上只有一种有两种不同的可视化方式):

  • 仅展示圆形。用户应该可以解释数字被截断/舍入。在您的示例中,显而易见6.67实际上是6.66666...

  • 根本不进行舍入,只需在固定的小数位后截断数字(如果需要,添加...;这实际上与其他解决方案类似)。

通常,如果您想要求解线性方程(或一般数学),请始终使用可用的最大精度的可用(且合理;性能明智)数据类型,通常是单精度值或双精度值。否则,你引入的错误边距会越来越差,你用它们计算得越多。

答案 1 :(得分:1)

这不是解决方案;只是对你想要达到的目标的更多数学描述(不判断这是否正确):

由于您将所有数字四舍五入为x小数,我们可以将这些数字视为整数(只需将它们乘以10 ^ x)。

现在,您正在尝试解决以下问题:

给定矩阵

A11+Adj11   A12+Adj12   ...   A1n+Adj1n
A21+Adj21   A22+Adj22   ...   A2n+Adj2n
A31+Adj31   A32+Adj32   ...   A3n+Adj3n
...         ...         ...   ...
Am1+Adjm1   Am2+Adjm2   ...   Amn+Adjmn

其中A11..Amn是常数整数,

查找整数Adj11 ... Adjmn

最小化和(abs(Adjxy))

(或者你更喜欢:最小化和((Adjxy)^ 2)

受制于:

- for each row m: Adjm1+Adjm2+...+Adjmn = - (Am1+Am2+...+Amn)
- for each col n: Adj1n+Adj2n+...+Adjmn = - (A1n+A2n+...+Amn)

这是一个integer programming问题,有m * n个变量和m + n个约束。您尝试最小化的功能不是线性的。

我担心这个问题远非微不足道。我相信您最好将其发布在https://math.stackexchange.com/

答案 2 :(得分:0)

使用浮点数时,无法消除舍入。您最好的解决方案可能是在矩阵中使用整数,然后将最终1/6应用于结果。

答案 3 :(得分:0)

确保小舍入误差不会导致总和出现大误差的常用方法是检查每个部分和的误差是否过大。

使用一维向量[a[1], a[2], ..., a[n]],您可以计算部分和[a[1], a[1]+a[2], ..., a[1]+a[2]+...+a[n]],将其相乘,然后通过将前一个单元格减去当前单元格来恢复正向量:[a[1]*b, (a[1]+a[2])*b-a[1]*b, ..., (a[1]+a[2]+...+a[n])*b-(a[1]+a[2]+...+a[n-1])*b]。通过使用这个技巧,任何部分和的误差不超过10 ^( - x)。

您可以使用以下3个程序将此方法用于2维矩阵:

partial_sum(M) =
  for i = 0 to n-1 do
    for j = 1 to m-1 do
      M[i][j] += M[i][j-1]
    done
  done
  for i = 0 to n-1 do
    for j = 1 to m-1 do
      M[j][i] += M[j-1][i]
    done
  done

multiply(M, a) =
  for i = 0 to n-1 do
    for j = 0 to m-1 do
      M[i][j] *= a
    done
  done

restore(M) =
  for i = 0 to n-1 do
    for j = 1 to m-1 do
      M[i][j] -= M[i][j-1]
    done
  done
  for i = 0 to n-1 do
    for j = 1 to m-1 do
      M[j][i] -= M[j-1][i]
    done
  done