Ruby矩阵计算中的浮点错误

时间:2017-12-12 21:33:33

标签: ruby eigenvector

我正在编写一些涉及查找给定矩阵的特征向量的代码,并且很惊讶Ruby在简单的情况下会产生一些不合理的结果。

例如,以下矩阵具有与特征值1相关联的特征向量:

> m = Matrix[[0r, 1/2r, 1/2r, 1/3r],
             [0r,  0r,  1/4r, 1/3r],
             [0r, 1/4r,  0r,  1/3r],
             [1r, 1/4r, 1/4r,  0r]]

Ruby发现特征值足够好,但特征向量爆炸:

> m.eigen.eigenvalues[2]
=> 1.0000000000000009

m.eigen.eigenvectors[2]
=> Vector[5.957702309312754e+15, 5.957702309312748e+15, 5.957702309312743e+15, 5.957702309312753e+15]

实际的特征向量应该是(7,4,4,9)。

难道不是这个麻烦吗?如果Ruby无法处理微小的矩阵,那么我们怎么可以信任呢?或者我做错了什么?

2 个答案:

答案 0 :(得分:0)

否,这并不麻烦。该矩阵可能不适用于特定的特征向量算法实现。毕竟Efficient and stable general eigenvector computation is nontrivial

Matrix库是从JAMA, a Java matrix package改编而来的,它表示它执行的是numerical computation而不是symbolic computation

  

未涵盖。 JAMA绝不是一个完整的线性代数环境……它专注于进行数值线性代数所需的原理数学功能

QR算法:数值计算

通过查看Matrix::EigenvalueDecomposition的源代码,我发现它命名了QR algorithm的用法。我不完全理解数学的复杂性,但我想我可能会理解为什么为什么会失败。计算机理如下:

  

在第k步(从k = 0开始),我们计算QR分解A k = Q k R k ...在某些条件下, [4] 矩阵A k 收敛到三角矩阵A的舒尔形式。三角矩阵的特征值列在对角线,并解决了特征值问题。

在“伪” Ruby中,这在概念上意味着:

working_matrix = orig_matrix.dup
all_q_matrices = []
loop do
  q, r = working_matrix.qr_decomposition
  all_q_matrices << q
  next_matrix = r * q
  break if difference_between(working_matrix, next_matrix) < accuracy_threshold
end
eigenvalues = working_matrix.diagonal_values

对于特征向量,它会继续:

  在收敛时,AQ =QΛ,其中Λ是A收敛到的特征值的对角矩阵,其中Q是到达那里所需的所有正交相似性变换的合成。因此,Q的列就是特征向量。

在“伪” Ruby中,继续:

eigenvectors = all_q_matrices.inject(:*).columns

数值计算中的浮点误差

我们可以看到,进行了一次数值计算的迭代来计算近似特征值,并且作为副作用,收集了一堆近似Q矩阵。然后,将这些近似的Q矩阵组合在一起以形成特征向量。

近似值的复合可能是导致极为不准确的结果的原因。 Math StackExchange发生灾难性取消的示例显示了simple quadratic computation with 400% relative error。您也许可以想象,具有重复算术运算的迭代矩阵算法可能会变得更糟。

一粒盐

再说一次,我对算法的数学和实现都没有深刻的了解,所以我不确切地知道 计算的哪些部分导致了特定的85110032990182200%错误,但是希望您现在能理解它是怎么发生的。

答案 1 :(得分:-2)

因为Ruby使用IEEE-754作为浮点精度标准。

众所周知,它有floating-point precision problem

所以尝试在ruby中使用十进制数字,它将解决此浮点数问题。