определяющая проблема точности matlab

У меня есть следующая программа

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

Аналитическое решение вышеупомянутой системы и та же программа, записанная в Фортране, выделяют значения omegan, равного 16,3818 и 32.7636 (значения Фортрана; аналитичный отличаются немного, но они там где-нибудь).

Так, теперь я задаюсь вопросом..., где я иду не так, как надо с этим? Почему matlab не дает ожидаемые результаты?

(это - вероятно, что-то ужасно простое, но оно дает мне головные боли),

6
задан gnovice 8 August 2017 в 04:26
поделиться

3 ответа

Новый ответ:

Вы можете исследовать эту проблему с помощью символьных уравнений, которые дадут мне правильные ответы:

>> 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

Я думаю, что вы либо просто не знали » t выбор значений в вашем цикле, достаточно близких к решениям для 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
ответ дан 17 December 2019 в 02:25
поделиться

Вы ищете слишком малые значения детерминанта, потому что 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))

Все, что я сделал на самом деле, - это записал значения определителя для всех значений омегана и построил логарифм этих значений детерминанта как функцию от омегана. Вот график:

alt text

Вы замечаете три основных провала на графике. Два совпадают с вашими результатами 16.3818 и 32.7636, но есть еще один, который вам не хватало (вероятно, потому, что ваше условие детерминанта меньше 1e-10 было слишком низким даже для вашего кода Fortran, чтобы его подобрать). Следовательно, Matlab также сообщает вам, что это значения омегана, которые вы искали, но поскольку определитель был определен в Matlab другим способом, значения не были одинаковыми - что неудивительно при работе с плохо обусловленными матрицами. . Кроме того, вероятно, это связано с Фортраном, использующим числа с плавающей запятой одинарной точности, как сказал кто-то другой. Я не буду разбираться, почему это не так, потому что я не хочу тратить на это свое время. Вместо этого давайте посмотрим, что вы пытаетесь сделать, и попробуем другой подход.

Вы, как я уверен, знаете, пытаетесь найти собственные значения матрицы

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

Это дает вам все четыре решения, а не только два, которые вы нашли с помощью своего кода на Фортране (хотя одно из них, нулевое, находилось за пределами вашего диапазона тестирования для 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)));

, который является алгоритмом, который, предположительно, использует det в соответствии с документами Matlab. Теперь я могу использовать 1E-10 в качестве условия, и он работает. Так, может быть, Matlab не вычисляет определитель точно так, как говорится в документации? Это немного тревожно.

3
ответ дан 17 December 2019 в 02:25
поделиться

Я поставил это как ответ, потому что не могу вставить это в комментарий: Вот как Matlab вычисляет определитель . Я предполагаю, что ошибки округления возникают из-за вычисления произведения нескольких диагональных элементов в U.

Алгоритм

Определитель вычисляется из треугольных множителей, полученных с помощью исключения Гаусса

[L,U] = lu(A) s =  det(L)        
%# This is always +1 or -1  
det(A) = s*prod(diag(U))
1
ответ дан 17 December 2019 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: