我有以下程序
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
上述系统的解析解,同样program written in fortran给出的omegan值等于16.3818和32.7636(fortran值;分析略有不同,但它们在某处)。
所以,现在我想知道......我在哪里错了?为什么matlab没有给出预期的结果?
(这可能非常简单,但令我头疼)
答案 0 :(得分:3)
你正在寻找太小的行列式值,因为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值的行列式值,并将这些决定因素值的对数绘制为omegan的函数。这是情节:
您注意到图表中有三个主要下降。两个与16.3818和32.7636的结果一致,但是还有一个你缺少的(可能是因为你的行列式小于1e-10的条件太低了,即使你的Fortran代码拿起它也是如此)。因此,Matlab也告诉你那些是你正在寻找的omegan的值,但是因为决定因素是在Matlab中以不同的方式确定的,所以这些值并不相同 - 在处理条件差的矩阵时也就不足为奇了。此外,正如其他人所说,它可能与使用单精度浮动的Fortran有关。我不打算研究为什么他们不是因为我不想浪费我的时间。相反,让我们看看你想要做什么,并尝试不同的方法。
我确信你知道,你正试图找到矩阵的特征值
a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0 0 2 -2]];
,将它们设为等于
-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
这为您提供了所有四种解决方案 - 不仅仅是您使用Fortran代码找到的两种解决方案(尽管其中一种,零,超出了omegan的测试范围)。如果你想通过检查Matlab中的行列式来解决这个问题,就像你一直试图做的那样,那么你将不得不使用你正在检查行列式的绝对值小于的值。我得到它的值为1e-4(它提供了3个解决方案:16.382,28.374和32.764)。
很抱歉这么长的解决方案,但希望它有所帮助。
<强>更新强>
在我上面的第一段代码中,我替换了
vals(i) = abs(det(a));
与
[L,U] = lu(a);
s = det(L);
vals(i) = abs(s*prod(diag(U)));
这是根据Matlab文档使用det的算法。现在,我可以使用1E-10作为条件并且它可以工作。那么也许Matlab并不像文档所说的那样完全计算行列式?这有点令人不安。
答案 1 :(得分:2)
新答案:
你可以使用符号方程来研究这个问题,它给出了正确的答案:
>> 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。
答案 2 :(得分:1)
我把它作为答案,因为我无法将其粘贴到评论中:以下是Matlab如何计算determinant。我假设舍入误差来自于计算U中多个对角元素的乘积。
算法
行列式是从 获得的三角因子 高斯消除
[L,U] = lu(A) s = det(L)
%# This is always +1 or -1
det(A) = s*prod(diag(U))