6

私は次のプログラムを持っています

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

上記のシステムの解析解、およびfortran で書かれた同じプログラムは、16.3818 と 32.7636 に等しいオメガの値を示します (fortran 値; 解析値は少し異なりますが、どこかにあります)。

だから、今私は疑問に思っています...これのどこが間違っているのでしょうか? matlab が期待される結果を出さないのはなぜですか?

(これはおそらく非常に単純なことですが、頭痛の種です)

4

3 に答える 3

3

Matlabが異なる行列式関数を使用しているため(または2つの異なる方法に含まれる浮動小数点の精度に関係する何かのような他の理由)、小さすぎる行列式の値を探しています。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))

私が実際に行ったことはすべて、オメガンのすべての値の行列式の値をログに記録し、それらの行列式の値のログをオメガンの関数としてプロットしたことです。プロットは次のとおりです。

代替テキスト

グラフに3つの大きな落ち込みがあります。2つは16.3818と32.7636の結果と一致しますが、欠落している追加の1つもあります(おそらく、行列式が1e-10未満であるという条件が低すぎて、Fortranコードでそれを取得できなかったためです)。したがって、Matlabは、これらが探していたオメガンの値であることも示していますが、行列式が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)

とオメガのために解決します。これは私がそれについて行った方法です:

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コードで見つけた2つだけでなく、4つすべてのソリューションが得られます(ただし、そのうちの1つであるゼロはomeganのテスト範囲外でした)。これまで行ってきたように、Matlabで行列式をチェックしてこれを解決したい場合は、行列式の絶対値がより小さいことをチェックしている値で遊ぶ必要があります。私はそれを1e-4の値で動作させました(16.382、28.374、および32.764の3つのソリューションを提供しました)。

このような長い解決策については申し訳ありませんが、うまくいけばそれが役立つでしょう。

アップデート:

上記のコードの最初のブロックで、

vals(i) = abs(det(a));

[L,U] = lu(a);
s = det(L);
vals(i) = abs(s*prod(diag(U)));

これは、Matlabのドキュメントによるとdetが使用していると思われるアルゴリズムです。これで、条件として1E-10を使用できるようになり、動作します。では、Matlabは、ドキュメントに記載されているとおりに行列式を計算していないのではないでしょうか。これはちょっと気がかりです。

于 2010-05-07T15:06:45.890 に答える
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、行列式がゼロにどれだけ近いかのしきい値が厳しすぎると思います。指定された値を に接続するaomegan = 16.3819(これは、ループが生成する 1 つのソリューションに最も近い値です)、次のようになります。

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

ans =

    2.765476845475786e-005

これは、1e-10 よりも絶対振幅がさらに大きくなります。

于 2010-05-07T14:19:34.493 に答える
1

これをコメントに貼り付けることができないため、これを回答として入れます。Matlab がdeterminantを計算する方法は次のとおりです。丸め誤差は、U の複数の対角要素の積を計算することから生じると思います。

アルゴリズム

行列式は、ガウス消去法で得られた三角因子から計算されます

[L,U] = lu(A) s =  det(L)        
%# This is always +1 or -1  
det(A) = s*prod(diag(U))
于 2010-05-07T15:58:15.037 に答える