matlab精度行列式问题

matlab精度行列式问题,matlab,matrix,fortran,precision,determinants,Matlab,Matrix,Fortran,Precision,Determinants,我有以下程序 format compact; format short g; clear; clc; L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3; for i=1:500000 omegan=1.+0.0001*i; a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0; a(2,1) = 1; a(2,2) = ((omegan

我有以下程序

format compact; format short g; clear; clc;  
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;  
for i=1:500000  
omegan=1.+0.0001*i;

a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0;
a(2,1) = 1; a(2,2) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(2,3) = 1; a(2,4) = 0;
a(3,1) = 0; a(3,2) = 1; a(3,3) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(3,4) = 1;
a(4,1) = 0; a(4,2) = 0; a(4,3) = 2; a(4,4) = ((omegan^2)*(Jm/(G*J))*d^2)-2;

if(abs(det(a))<1E-10) sprintf('omegan= %8.3f det= %8.3f',omegan,det(a))
end          
end
格式紧凑;格式缩写g;清楚的clc;
L=140;J=77;Jm=10540;G=0.8*10^8;d=L/3;
对于i=1:500000
ω=1.+0.0001*i;
a(1,1)=((ω根^2)*(Jm/(G*J))*d^2)-2;a(1,2)=2;a(1,3)=0;a(1,4)=0;
a(2,1)=1;a(2,2)=((ω根^2)*(Jm/(G*J))*d^2)-2;a(2,3)=1;a(2,4)=0;
a(3,1)=0;a(3,2)=1;a(3,3)=((ω根^2)*(Jm/(G*J))*d^2)-2;a(3,4)=1;
a(4,1)=0;a(4,2)=0;a(4,3)=2;a(4,4)=((ω根^2)*(Jm/(G*J))*d^2)-2;

如果(abs(det(a))新答案:

你可以用符号方程来研究这个问题,这给了我正确的答案:

>> clear all             %# Clear all existing variables
>> format long           %# Display more digits of precision
>> syms Jm d omegan G J  %# Your symbolic variables
>> a = ((Jm*(d*omegan)^2)/(G*J)-2).*eye(4)+...  %# Create the matrix a
       diag([2 1 1],1)+...
       diag([1 1 2],-1);
>> solns = solve(det(a),'omegan')  %# Solve for where the determinant is 0

solns =

                                0
                                0
            (G*J*Jm)^(1/2)/(Jm*d)
           -(G*J*Jm)^(1/2)/(Jm*d)
       -(2*(G*J*Jm)^(1/2))/(Jm*d)
        (2*(G*J*Jm)^(1/2))/(Jm*d)
  (3^(1/2)*(G*J*Jm)^(1/2))/(Jm*d)
 -(3^(1/2)*(G*J*Jm)^(1/2))/(Jm*d)

>> solns = subs(solns,{G,J,Jm,d},{8e7,77,10540,140/3})  %# Substitute values

solns =

                   0
                   0
  16.381862247021893
 -16.381862247021893
 -32.763724494043785
  32.763724494043785
  28.374217734436371
 -28.374217734436371
我认为您可能只是没有在循环中选择与
omegan
的解足够接近的值,或者您的行列式接近于零的阈值太严格。当我将给定值插入
a
,以及
omegan=16.3819
(这是与您的循环生成的解最接近的值),我明白了:

>> det(subs(a,{omegan,G,J,Jm,d},{16.3819,8e7,77,10540,140/3}))

ans =

    2.765476845475786e-005

绝对振幅仍然大于1e-10。

您寻找的行列式值太小,因为Matlab使用的是不同的行列式函数(或其他原因,例如与两种不同方法中涉及的浮点精度有关).我将向您展示Matlab基本上为您提供了正确的值和更好的方法来解决这个问题

首先,让我们对您的代码稍加修改

format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
vals = zeros(1,500000);
for i=1:500000
    omegan=1.+0.0001*i;

    a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0;
    a(2,1) = 1; a(2,2) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(2,3) = 1; a(2,4) = 0;
    a(3,1) = 0; a(3,2) = 1; a(3,3) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(3,4) = 1;
    a(4,1) = 0; a(4,2) = 0; a(4,3) = 2; a(4,4) = ((omegan^2)*(Jm/(G*J))*d^2)-2;
    vals(i) = abs(det(a));
    if(vals(i)<1E-10)
        sprintf('omegan= %8.3f det= %8.3f',omegan,det(a))
    end
end
plot(1.+0.0001*(1:500000),log(vals))
,将它们设置为等于

-omegan^2*(Jm/(G*J)*d^2)
为omegan求解。我就是这样做的:

format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
C1 = (Jm/(G*J)*d^2);
a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0,0,2,-2]];
myeigs = eig(a);
myeigs(abs(myeigs) < eps) = 0.0;
for i=1:4
    sprintf('omegan= %8.3f', sqrt(-myeigs(i)/C1))
end


根据Matlab文档,这就是det应该使用的算法。现在,我可以使用1E-10作为条件,并且它可以工作。因此,也许Matlab没有像文档所说的那样精确地计算行列式?这有点令人不安。

我把它作为一个答案,因为我无法将其粘贴到注释中:以下是Matlab的计算方法我假设舍入误差来自于计算多个对角线元素的乘积,单位为U

算法

行列式是根据 三角因子由 高斯消去


你好,格诺维奇,我希望你能过来一下:)不,那里的“少于”标志没问题(除非我遗漏了你想要暗示的东西)。这是振动中的特征值问题。。。我需要找到所有ω(固有频率),其中determint为零。它们的数量是无限的,但我只寻找前几个(两个或三个)。然而,我无法理解的是,为什么我的fortran程序会毫无问题地“吞咽”它,而det()函数却不会。这似乎也不是一个单精度/双精度的问题——fortran程序是单精度的,默认情况下,在matlab中,一切都是双精度的。所以matlab从一开始就应该有优势,sprintf是多余的,它只是为了让那些试图解决这个问题的人不必自己添加它。正如我所说,我已经知道这个案例的结果。我对这个错误的原因更感兴趣,因为我现在不知道在解决一个更大的问题(我不知道结果)时,我是否可以依靠matlab的机制。@Idigas:我给出了一个全新的答案。希望对你有帮助-谢谢!到目前为止,我还没有尝试过符号工具箱,因为组装系数矩阵的例程已经完成了。另外,我可能无法使用它,因为矩阵通常比这个复杂一点(这只是一个简单的梁,分成3个元素)。但正如我刚才在对问题的评论中写给乔纳斯的那样,我不明白。对于omegan我有相同的步骤,我有相同的停止标准。为什么在双精度下工作的matlab没有给出合适的结果?很有趣。对我来说,它也从未停止过。我得到的det(a)的值是-4E-5和-3E-4(如果我没有犯错误的话)。只是为了检查错误:您是否从fortran程序中获取了det(a)的值列表,并将其与Matlab中的值进行比较?@Jonas-不,我认为这是多余的。毕竟,我只是将fortran程序复制(做了必要的修改)到matlab中,由于matlab默认在dp模式下工作,我相信它会毫无问题地解决它。正如我在对gnovice的评论中所说,这只是一个例子——我对结果不太感兴趣,对fortran和matlab之间的差异也不太感兴趣(我仍在测试matlab是否能处理此类问题)。@Idigas:我知道你对这个具体问题并不特别感兴趣。但如果这真的是一个精度问题,你不想知道在什么条件下会发生吗?另外,正如其他人所指出的:Matlab确实找到了解决方案,只是截止点可能不同。@Idigas:欢迎来到数值计算。我们在不同的操作系统上使用完全相同的优化代码运行程序时遇到问题。通过比较数值,您可以了解精度误差的来源。例如,
det(a)
可能几乎相同,只要它在上面,比如1E-3,并且Fortran系统性地为行列式返回接近零的值(如果它变小)。这可能会让您了解在从一个程序移植到另一个程序时需要如何调整公差。@Jonas-True;一个值得尝试的想法。我要去试试。至于在不同的平台上运行使用相同代码的程序,我不知道matlab,但fortran使用种类说明符在该部分提供了非常“好”的特性。它使您能够指定所需的精度和类型范围,从而降低了程序的平台可靠性(REAL*4依赖于平台,具体取决于*4在什么处理器/平台/编译器上的含义。我相信它是fortran95的标准,并且是其中一个无价的功能,这可能是问题所在(ma
format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
C1 = (Jm/(G*J)*d^2);
a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0,0,2,-2]];
myeigs = eig(a);
myeigs(abs(myeigs) < eps) = 0.0;
for i=1:4
    sprintf('omegan= %8.3f', sqrt(-myeigs(i)/C1))
end
vals(i) = abs(det(a));
[L,U] = lu(a);
s = det(L);
vals(i) = abs(s*prod(diag(U)));
[L,U] = lu(A) s =  det(L)        
%# This is always +1 or -1  
det(A) = s*prod(diag(U))