数值分析(应用数学)课程常用matlab算法

数值分析(应用数学)课程常用matlab算法

  • 数值分析(应用数学)课程常用matlab算法
    • 代数方程组求解
      • Gauss消元方法(列主元素)
      • 追赶法
      • LDU分解
      • 迭代法
      • 不动点法
      • 牛顿迭代法
    • 函数插值
      • 牛顿插值(差商)
    • 数值积分
      • 复化梯形、复化Simpson积分
      • Romberg 积分算法
    • 常微分方程
      • 改进欧拉法
      • 经典四阶Runge-Kutta 法

数值分析(应用数学)课程常用matlab算法

数值计算是工科专业经常接触到的课程,介绍的算法包括代数方程组求解、函数插值、数值积分与微分、常微分方程求解。本文不对算法原理进行介绍,读者可参考应用数学、数值分析、工程数学等教材。(能找过来的同学估计都是上过课的)

代数方程组求解

线性方程组:Gauss消元方法(列主元素),追赶法,迭代法
非线性方程组:不动点法、牛顿迭代法

Gauss消元方法(列主元素)

function [x] = myGauss(A,B)
% Gauss消元方法(列主元素)求解方程组
%   此处显示详细说明
% A 系数矩阵
% B b向量
[n1,n2]=size(A);
n=length(B);
if (n1~=n || n2~=n)
    error("参数输入有误");
end
if isrow(B)
    B=B';
end
disp('增广矩阵A|B为:');
disp([A,B]);
x=zeros(n,1);
for i=1:n-1
    [~,m_index]=max(abs(A([i:n],i)));
    m_index=m_index+i-1;
    if (i~=m_index)
        A([i,m_index],:)=A([m_index,i],:);
        B([i,m_index])=B([m_index,i]);
        disp(['交换第' num2str(i) '和第' num2str(m_index) '行:']);
        disp([A,B]);
    end
    
    for j=i+1:n
        l=A(j,i)/A(i,i);
        A(j,:)=A(j,:)-A(i,:)*l;
        B(j)=B(j)-B(i)*l;
    end
    disp(['第' num2str(i) '次消元:']);
    disp([A,B]);
end
%回代
x(n)=B(n)/A(n,n);
for i=n-1:-1:1
    sum=0;
    for k=i+1:n
        sum=sum+A(i,k)*x(k);
    end
    x(i)=(B(i)-sum)/A(i,i);
end
disp('方程组的解为:');
disp(x);
end

追赶法

数值分析(应用数学)课程常用matlab算法_第1张图片
输入参数a,b,c,f分别为上图中的ai,bi,ci,fi写成数组形式

function [x] = zhuiganfa(a,b,c,f)
% 追赶法解三对角方程组
% a,b,c皆为行向量
na=length(a);
nb=length(b);
nc=length(c);
n=length(f);
if (any([na+1,nb,nc+1,n]-n))
    error("参数输入有误");
end

a=[0 a]; 
A=zeros(n,n);
for i=1:n
    A(i,i)=b(i);
end
for i=1:n-1
    A(i+1,i)=a(i+1);
    A(i,i+1)=c(i);
end
disp('方程组增广矩阵为:');
disp([A,f']);

l=zeros(1,n);
y=zeros(1,n);
x=zeros(1,n);

l(2)=a(2)/b(1);
for i=3:n
    l(i)=a(i)/(b(i-1)-c(i-2)*l(i-1));
end
disp(['l2 … l' num2str(n) '分别为:']);
disp(l(2:n));
y(1)=f(1);
for i=2:n
    y(i)=f(i)-l(i)*y(i-1);
end
disp(['y1 … y' num2str(n) '分别为:']);
disp(l([2:n]));
x(n)=y(n)/(b(n)-c(n-1)*l(n));
for i=n-1:-1:2
    x(i)=(y(i)-c(i)*x(i+1))/(b(i)-c(i-1)*l(i));
end
x(1)=(y(1)-c(1)*x(2))/b(1);
disp('方程组的解为:');
disp(x);
end

LDU分解

包括Doolittle分解,Crout分解,LDU分解

function [L,D,U]=LDU(A,t)
% 对矩阵A进行分解
% t参数对应'Doo''Cro''LDU',默认Doolittle分解
if nargin<2
    t='Doo';
end
b=size(A);
n=b(1);
if b(1)~=b(2)
    error('A不是方阵');
end
if n~=rank(A)
    error('A不满秩');
end

%初始化
L=eye(n,n);
D=zeros(n,n);
U=zeros(n,n);

for k=1:n
    for j=k:n
        sum_j=0;
        sum_i=0;
        for r=1:k-1
            sum_j=sum_j+L(k,r)*U(r,j);
            sum_i=sum_i+L(j,r)*U(r,k);
        end
        U(k,j)=A(k,j)-sum_j;
        L(j,k)=(A(j,k)-sum_i)/U(k,k);
    end
    D(k,k)=U(k,k);
end

L_1=L*D; % Crout分解的L,下三角矩阵
U_1=D^(-1)*U; % Crout分解的U,单位上三角矩阵

if strcmp(t,'Doo')
    disp('矩阵的Doolittle分解:');
    disp('  L=');  disp(L);
    disp('  U=');  disp(U);
    D=U;
elseif strcmp(t,'Cro')
    disp('矩阵的Crout分解:');
    disp('  L=');  disp(L_1);
    disp('  U=');  disp(U_1);
    L=L_1;
    D=U_1;
elseif strcmp(t,'LDU')
    disp('矩阵的LDU分解:');
    disp('  L=');  disp(L);
    disp('  D=');  disp(D);
    disp('  U='); disp(U_1);
    U=U_1;
end

迭代法

包括Jacobi法、Gauss-Seidel法、SOR法

function [x] = diedai(A,b,x0,s,e)
% 迭代法求解线性方程组
% A为方阵,b为列向量,x0为初始向量
% s取123分别对应Jacobi法、Gauss-Seidel法、SOR法
% e 求解精度,默认0.0001
if nargin < 5
    e=0.0001;
    if nargin < 4
        s=1;
    end
end
if isrow(b)
    b=b';
end
format long
[m,n]=size(A);
n1=length(b);
if m~=n || n1~=n
    error("输入参数维度有误");
end
% format long;
D=zeros(n);
L=zeros(n);
U=zeros(n);
for i=1:n
    D(i,i)=A(i,i);
    for j=i+1:n
        U(i,j)=-A(i,j);
        L(j,i)=-A(j,i);
    end
end
if s==1
    M=D^(-1)*(L+U);
    f=D^(-1)*b;
elseif s==2
    M=(D-L)^(-1)*U;
    f=(D-L)^(-1)*b;
elseif s==3
    w=input('请输入松弛因子w:');
    M=(D-w*L)^(-1)*((1-w)*D+w*U);
    f=w*(D-w*L)^(-1)*b;
else
    warning('指定算法参数有误,已使用Jacobi迭代法求解')
    M=D^(-1)*(L+U);
    f=D^(-1)*b;
end
N=1; %迭代次数
d=1; %精度
N0=30; %最大迭代次数
while N<=N0 && d>e
    x=M*x0+f;
    disp(['第',num2str(N),'次迭代近似解']);
    disp(sprintf('%.5f    ',x')); %#ok<DSPS>
    d=max(abs(x-x0));
    N=N+1;
    x0=x;
end
end

不动点法

function [x] = budongdian(G,x,x0,e)
% 不动点求解非线性方程组
% G 不动点映射(sym类型)
% x 待求解变量
if nargin<4
    e=0.0001;
end
x=sym(x);
N=1; %迭代次数
N0=30; %最大迭代次数
d=1; 
format long
while N<=N0  && d>e
    x1=vpa(subs(G,x,x0));
    disp(['第',num2str(N),'次迭代近似解']);
    disp(sprintf('%.8f',x1)); %#ok<DSPS>
    d=norm(x1-x0);
    N=N+1;
    x0=x1;
end
x=double(x1);
end

牛顿迭代法

function [x] = Newton1(f,x,x0,e)
% Newton迭代法求解一维非线性函数零点
% f 待求解函数(sym类型)
% x 待求解变量
if nargin<4
    e=0.0001;
end
x=sym(x);
df=diff(f,x);
N=1; %迭代次数
N0=30; %最大迭代次数
d=1; %精度
format long
while N<=N0  && d>e
    x1=x0-vpa(subs(f,x,x0)/subs(df,x,x0));
    disp(['第',num2str(N),'次迭代近似解']);
    disp(sprintf('%.8f',x1)); %#ok<DSPS>
    d=norm(x1-x0);
    N=N+1;
    x0=x1;
end
x=double(x1);
end

函数插值

牛顿插值(差商)

function [y,C,R] = Newton(x,X,Y,n)
%求x处牛顿插值结果y、差商表、其误差估计
%输入:X是n+1个节点横坐标向量,Y是纵坐标向量
%输出:C为差商表,R为估计误差f~(n+1)(x)的系数

%format long
xn=length(X);yn=length(Y);
if xn~=yn
    error("输入节点错误");
else
    if nargin < 4
        n=xn-1;
    end
    if xn < n+1
    error("输入节点数量错误");
    end
end
C=zeros(xn,xn+1);
if isrow(X)
    C(:,1) = X';
    C(:,2) = Y';
else
    C(:,1) = X;
    C(:,2) = Y;
end
for j=3:xn+1
    for i=j-1:xn
        C(i,j)=( C(i,j-1)-C(i-1,j-1) )/( C(i,1)-C(i+2-j,1) );
    end
end
fprintf('    x         f(x)      ');
for g=1:n
    fprintf('%d阶差商   ',g);
end
fprintf('\n');
disp(C);


y=0;
for k=1:n+1
    w=1;
    for m=1:k-1
        w=w*(x-C(m,1));
    end
    y=y+C(k,k+1)*w;
end

%误差估计
w=1;
for i=1:xn
    w=w*(x-X(i));
end
R=w/factorial(n+1);

数值积分

复化梯形、复化Simpson积分

function [result] = fuhuajifen(f, x_Low, x_Up, n, a)
% 数值积分。a=1(默认):复化梯形  a=2:复化 Simpson
%        f    :被积函数句柄
%        x_Low:积分区间下界
%        x_Up :积分区间上界
%        n    :等分数量
if nargin < 5
    a=1;
    if nargin < 4
        error('参数过少')
    end
end

h = (x_Up - x_Low)/n; 
result = 0;
if a==1
    for i = 1:n
        result = result + h/2*(f(x_Low+h*(i-1))+f(x_Low+h*i));
    end
elseif a==2
    for i = 1:n
        result = result + h/6*(f(x_Low+h*(i-1))+4*f(x_Low+h*(i-1)+h/2)+f(x_Low+h*i));
    end
else
    error('选择算法序号有误')
end

end 

Romberg 积分算法

function [result] = Romberg(f, x_Low, x_Up, e)
%  Romberg 数值积分
%        f    :被积函数句柄
%        x_Low:积分区间下界
%        x_Up :积分区间上界
%        e    :精度(默认0.0001if nargin < 4
    e=0.0001;
    if nargin < 3
        error('参数过少')
    end
end
c=10; %Romberg算法过程表的初始行数目
R=zeros(c,4);
for k=0:4
    n=2^k;
    h = (x_Up - x_Low)/n;
    T=0;
    for i = 1:n
        T = T + h/2*(f(x_Low+h*(i-1))+f(x_Low+h*i));
    end
    R(k+1,1)=T;
end
for j=2:4
    a=4^(j-1);
    for i=1:(6-j)
        R(i,j)=(a*R(i+1,j-1)-R(i,j-1))/(a-1);
    end
end
ee=R(2,4)-R(1,4);
while ee>e
    k=k+1;
    n=2^k;
    h = (x_Up - x_Low)/n;
    T=0;
    for i = 1:n
        T = T + h/2*(f(x_Low+h*(i-1))+f(x_Low+h*i));
    end
    R(k+1,1)=T;
    for j=2:4
        a=4^(j-1);
        R(k-j+2,j)=(a*R(k-j+3,j-1)-R(k-j+2,j-1))/(a-1);
    end
    ee=R(k-2,4)-R(k-3,4);
end
disp('        T      S      C      R');
disp(R(1:k+1,:))
result=R(k-2,4);

常微分方程

改进欧拉法

function [y] = myEuler(f, x0, y0, x)
% 改进Euler法
%        f :微分方程函数句柄 y'=f(x,y)
%        x0:初始x值 x0
%        y0:初始y值 y(x0)
%        x :待求x值,可以为数组
if nargin < 4
    error("输入参数太少");
end
x=sort(x);
if x0 > min(x)
    [xx,index] = sort([x0,x]);
    d=find(index==1);
    xx1=fliplr(xx(1:d));
    [yy1] = fEuler(f, xx1, y0);
    yy1=fliplr(yy1);
    xx2=xx(d:end);
    [yy2] = fEuler(f, xx2, y0);
    y=[yy1(1:end-1),yy2(2:end)];
    disp(x); disp(y);
else
    xx3=[x0,x];
    [yy3] = fEuler(f, xx3, y0);
    y=yy3(2:end);
    disp(x); disp(y);
end
end

function [yyn] = fEuler(ff, xxn, y00)
% 子函数
l=length(xxn);
yyn=zeros(1,l); yyn(1)=y00;
for i=2:l
    h=xxn(i)-xxn(i-1);
    yb=yyn(i-1)+h*ff(xxn(i-1),yyn(i-1));
    yyn(i) = yyn(i-1)+h/2*(ff(xxn(i-1),yyn(i-1))+ff(xxn(i),yb));
end
end

经典四阶Runge-Kutta 法

function [x, y] = RungeKutta4(f, x0, y0, x)
% 四阶 Runge-Kutta 法解一阶常微分方程
%        f :微分方程函数句柄 y'=f(x,y)
%        x0:初始x值 x0
%        y0:初始y值 y(x0)
%        x :待求x值,可以为数组
if nargin < 4
    error("输入参数太少");
end
x=sort(x);
if x0 > min(x)
    [xx,index] = sort([x0,x]);
    d=find(index==1);
    xx1=fliplr(xx(1:d));
    [yy1] = fRK(f, xx1, y0);
    yy1=fliplr(yy1);
    xx2=xx(d:end);
    [yy2] = fRK(f, xx2, y0);
    y=[yy1(1:end-1),yy2(2:end)];
    disp(x); disp(y);
else
    xx3=[x0,x];
    [yy3] = fRK(f, xx3, y0);
    y=yy3(2:end);
    disp(x); disp(y);
end
end


function [yyn] = fRK(ff, xxn, y00)
% 子函数
l=length(xxn);
yyn=zeros(1,l); yyn(1)=y00;
for i=1:l-1
    h=xxn(i+1)-xxn(i);
    k1 = ff(xxn(i), yyn(i));
    k2 = ff(xxn(i)+0.5*h, yyn(i)+k1*h/2);
    k3 = ff(xxn(i)+0.5*h, yyn(i)+k2*h/2);
    k4 = ff(xxn(i)+h, yyn(i)+ k3*h);
    yyn(i+1) = yyn(i)+h*(k1+2*k2+2*k3+k4)/6;
end
end

你可能感兴趣的:(数值分析(应用数学)课程常用matlab算法)