Matlab的行列式函数出了问题



以下是我的一个程序的摘录:

function [P] = abc(M,f); if det(M) ~= 1, disp(['Matrix M should have determinant 1'])

我允许用户选择不为"f"输入值。

当我运行abc([2 1;1 1])时,程序运行良好,它做了它应该做的事情。但当我运行abc([6 13;5 11])时,我被告知"矩阵M应该有行列式1"。

到底发生了什么事?

编辑:在命令窗口中,我输入了以下内容:

M = [6 13; 5 11]; if det(M) ~= 1, disp('Im broken'); end

然后Matlab自己告诉我它坏了。

感谢

欢迎来到浮点运算的奇妙世界。MATLAB使用LU分解(即线性代数)来计算行列式。它之所以这么做,是因为行列式对于大小适中的数组来说效率极低,除非它这样做。

LU分解的结果是,行列式被计算为浮点数。这不是一个问题,除非你输入了一个像你输入的那样简单的问题——一个仅由小整数组成的2x2矩阵的行列式。在这种情况下,行列式本身也是一个(合理的)小整数。因此,你可以通过使用教科书公式,简单地自己计算2x2矩阵的行列式来解决这个问题。

D=A(1,1)*A(2,2)-A(1,2)*A;

这对于小整数矩阵A来说是完全正确的,尽管即使这样也可能显示出某些矩阵的精度损失。例如,考虑简单的2x2矩阵A:

>> A = [1e8 1;1 1e8];

我们知道这个矩阵的行列式是1e16-1。

>> det(A)
ans =
                     1e+16

当然,MATLAB将其显示为1e16。但实际上,在MATLAB中,det函数生成的数字实际上是9999999999999998,所以1e16-2。同样糟糕的是,如果我使用上面给出的2x2行列式的公式,它会返回一个仍然不正确的结果,10000000000000000。两个结果相差1。您可以通过查看eps的帮助来了解更多关于这些问题的信息。

我的观点是,有些2x2矩阵的行列式计算会有问题,即使它们是整数矩阵。

一旦你的矩阵变成非整数,那么事情就会变成真正的浮点数,而不是整数。这意味着你必须简单地使用与公差的比较,而不是测试精确的统一性。无论如何,这是一条好规则。当你测试平等时,一定要使用宽容,至少在你学会了什么时候不遵守规则之前!

所以,你可以选择这样的测试:

if abs(det(A) - 1) < (10*eps(1))
  warning('The sky is falling! det has failed me.')
end

注意,我使用了eps(1),因为我们将事物与1进行比较。事实上,我把eps乘以10,在计算行列式时会有一点斜率。

最后,你应该知道,无论你在这里使用行列式进行什么测试,通常都是BBBBBBBBAAAAAAAAAADDDDDDDD!是的,也许你的老师让你这么做,或者你在课本上发现了一些东西。但是行列式对于数值计算来说是一件坏事。行列式几乎总是有可供选择的。同样,这被称为判断,知道什么时候你被告知要使用的东西实际上是错误的

由于浮点数的限制,您遇到了标准问题。det函数的结果可能类似于1.00000001。

一般经验法则:永远不要测试浮点值是否相等。

让您深入了解:det不是使用您在线性代数中学习的旧公式计算的,而是使用更有效的算法。

例如,使用高斯消去法,可以在等效的上三角矩阵中变换M,然后将行列式计算为主对角线的乘积(下三角为全零)。

M = [6 13; 5 11]
G = M - [0 0; M(2,1)/M(1,1) * M(1,:)];

理论上det(M)等于det(G),即6*1/6=1,但作为G浮点,而不是数矩阵,G(1,1)*G(2,2)~=1

事实上,G(1,1)G(2,2)并不完全是1和1/6,但它们的相对误差很小(见eps,在大多数机器上约为2.22e-16)。它们的实际值约为6*(1+eps)和1/6*(1+eps),因此它们的乘积也会有小误差。

我不确定Matlab是使用高斯消去法还是类似的LU分解法。

最新更新