老感觉昨天自己最后写的那个python牛顿法求解,老觉得不太对,,其实后面我想学完Fortran之后,再跟着matlab书把数据处理再学一下,因为Fortran那本书讲的东西实在是太少了。,而且听师兄说,我们不用Fortran绘图,后面还是matlab和python来绘图。
今天先不说了,直接开始矩阵运算,其实矩阵的加减法没啥好说的,就是相同位置进行加减运算就行了,主要是乘法,Fortran库里有一个matmul()函数来计算,但是今天还是先自己敲吧。
program main
implicit none
integer::a(3,3)
integer::b(3,3)
integer::c(3,3)
integer i,j,k
data a / 1,2,3,4,5,6,7,8,9 /
data b /10,11,12,13,14,15,16,17,18/
! 加法
!可以直接使用c=a+b,下面是为了展示运算过程
do i=1,3
do j=1,3
c(i,j)=a(i,j)+b(i,j)
end do
end do
! 减法
!可以直接使用c=a-b,下面是为了展示运算过程
do i=1,3
do j=1,3
c(i,j)=a(i,j)-b(i,j)
end do
end do
! 乘法
do i=1,3
do j=1,3
c(i,j)=0
do k=1,3
c(i,j)=c(i,j)+a(i,k)*b(k,j)
end do
end do
end do
! 再试试Fortran自带的函数matmul
c=MATMUL(a,b)
write(*,"(I5,I5,I5/I5,I5,I5/I5,I5,I5)")c
stop "over"
end program
放心,没问题的,ctrl+c,ctrl+v之后完全可以运行。
其实也可以在主程序外面把这几个运算方法写成function或者subroutine,我觉得都还行,就是个传参嘛。反正我是没有用书上的代码,习惯了,不喜欢整个程序纯粹用大写字母。
1、三角矩阵:上三角和下三角,上三角对角线以下的数全部是0,相应的,下三角对角线以上的全部是零:
跟着书上的代码敲一遍吧,我线代的储备主要还是考研时候听网课攒的点底子(大二学线代的时候才考了85+,有点低)
module LinearAlgebra
implicit none
contains
subroutine output(matrix)
implicit none
integer::m,n
real::matrix(:,:)
integer::i
CHARACTER(len=20)::for='(??(1x,f6.3))'
m=size(matrix, dim=1)
n=size(matrix, dim=2)
WRITE(for(2:3),'(I2)')N
do i=1,N
write(*,Fmt=for)matrix(i,:)
end do
return
end subroutine
! 求解上三角矩阵:
subroutine upper(matrix)
implicit none
integer::m,n
real::matrix(:,:)
integer::i,j
real::e
m=size(matrix, dim=1)
n=size(matrix, dim=2)
do I=1,n-1
do j=i+1,m
e=matrix(j,i)/matrix(i,i)
matrix(j,i:m)=matrix(j,i:m)-matrix(i,i:m)*e
end do
end do
return
end subroutine
! 求解下三角矩阵:
subroutine lower(matrix)
implicit none
integer::m,n
real::matrix(:,:)
integer::i,j
real::e
m=size(matrix, dim=1)
n=size(matrix, dim=2)
do I=n,2,-1
do j=i-1,1,-1
e=matrix(j,i)/matrix(i,i)
matrix(j,1:i)=matrix(j,1:i)-matrix(i,1:i)*e
end do
end do
return
end subroutine
end module
program main
use LinearAlgebra
implicit none
INTEGER,PARAMETER::n=3
real::a(n,n),b(n,n)
data a / 1,2,1,3,2,3,2,3,4 /
write(*,*)"Matrix A:"
CALL output(a)
b=a
write(*,*)"Upper:"
CALL upper(b)
CALL output(b)
b=a
write(*,*)"lower:"
CALL upper(b)
CALL output(b)
stop "over"
end program
输出:
学习上下三角矩阵的目的就是,可以应用在determinant、gauss-jordan发求解联立式、求逆矩阵等。
下午如果有时间的话我就学着写写determinant、gauss-jordan和求逆矩阵如果没时间的话那就算了。
哈哈,下午有时间!
Determinant:就是把矩阵转化成上三角矩阵,然后求行列式值,把这段代码加到module里面就可以调用。
real function Determinant(matrix)
real::matrix(:,:)
real,ALLOCATABLE::ma(:,:)
integer::i,n
n=size(matrix, dim=1)
ALLOCATE(ma(n,n))
ma=matrix
CALL upper(ma)
Determinant=1.0
do i=1,n
Determinant=Determinant*ma(i,i)
end do
end function
Gauss-Jordan法求联立方程式:
subroutine Gauss_Jordan(a,s,ans)
real::a(:,:)
real::s(:)
real::ans(:)
real,ALLOCATABLE::b(:,:)
integer :: i
integer :: n
n=size(a, dim=1)
ALLOCATE(b(n,n))
b=a
ans=s
call upper1(b,ans,n)
call lower1(b,ans,n)
do i=1,n
ans(i)=ans(i)/b(i,i)
end do
RETURN
end subroutine
subroutine output1(m,s)
implicit none
real::m(:,:),s(:)
integer i,j,n
n=size(m, dim=1)
do i=1,n
write(*,"(1x,f5.2,a1)",advance="no")m(i,1),'a'
do j=2,n
if(m(i,j)<0)then
write(*,"('-',f5.2,a1)",advance="no")-m(i,j),char(64+j)
else
write(*,"('+',f5.2,a1)",advance="no")m(i,j),char(64+j)
end if
end do
end do
end subroutine
subroutine upper1(matrix,s,n)
implicit none
integer::n
real::matrix(n,n)
real::s(n)
integer::i,j
real::e
do I=1,n-1
do j=i+1,n
e=matrix(j,i)/matrix(i,i)
matrix(j,i:n)=matrix(j,i:n)-matrix(i,i:n)*e
s(j)=s(j)-s(i)*e
end do
end do
return
end subroutine
! 求解下三角矩阵:
subroutine lower1(matrix,s,n)
implicit none
integer::n
real::matrix(:,:)
real::s(n)
integer::i,j
real::e
do I=n,2,-1
do j=i-1,1,-1
e=matrix(j,i)/matrix(i,i)
matrix(j,1:n)=matrix(j,1:n)-matrix(i,1:n)*e
s(j)=s(j)-s(i)*e
end do
write(*,"('=',f8.4)")s(i)
end do
return
end subroutine
上面两段代码加到module里面就好,直接运行。
Gauss_Jordan是用来求解方程组的。
逆矩阵,实际上书上介绍的方法就是在要求逆矩阵的矩阵后面加上一个单位矩阵,然后把前者处理成单位矩阵,前者每一次处理的时候,后者要跟着进行相同的操作,之后得到的就是逆矩阵。
subroutine inverse(a,b)
implicit none
real::a(:,:),b(:,:)
real,ALLOCATABLE::c(:,:)
integer i,j,n
n=size(a, dim=1)
allocate(c(n,n))
forall(i=1:n,j=1:n,i==j)b(i,j)=1.0
forall(i=1:n,j=1:n,i/=j)b(i,j)=0.0
c=a
call upper1(c,b,n)
call lower1(c,b,n)
forall(i=1:n)b(i,:)=b(i,:)/b(i,i)
return
end subroutine
这下求出来的就是matrix的逆矩阵啦,同样的,上面的subroutine直接加到module里面就可以调用它了。
至于使用嘛,就看你到底要处理什么问题了,比如说求解下面的对角矩阵啊,解方程组之类的,都可以,具体情况具体看待。
ok,把今天的完整代码附上:
module LinearAlgebra
implicit none
contains
! Determinant矩阵
real function Determinant(matrix)
real::matrix(:,:)
real,ALLOCATABLE::ma(:,:)
integer::i,n
n=size(matrix, dim=1)
ALLOCATE(ma(n,n))
ma=matrix
CALL upper(ma)
Determinant=1.0
do i=1,n
Determinant=Determinant*ma(i,i)
end do
end function
! 求解联立方程组
subroutine Gauss_Jordan(a,s,ans)
real::a(:,:)
real::s(:)
real::ans(:)
real,ALLOCATABLE::b(:,:)
integer :: i
integer :: n
n=size(a, dim=1)
ALLOCATE(b(n,n))
b=a
ans=s
call upper1(b,ans,n)
call lower1(b,ans,n)
do i=1,n
ans(i)=ans(i)/b(i,i)
end do
RETURN
end subroutine
! 逆矩阵求解
subroutine inverse(a,b)
implicit none
real::a(:,:),b(:,:)
real,ALLOCATABLE::c(:,:)
integer i,j,n
n=size(a, dim=1)
allocate(c(n,n))
forall(i=1:n,j=1:n,i==j)b(i,j)=1.0
forall(i=1:n,j=1:n,i/=j)b(i,j)=0.0
c=a
call upper1(c,b,n)
call lower1(c,b,n)
forall(i=1:n)b(i,:)=b(i,:)/b(i,i)
return
end subroutine
! 输出
subroutine output(matrix)
implicit none
integer::m,n
real::matrix(:,:)
integer::i
CHARACTER(len=20)::for='(??(1x,f6.3))'
m=size(matrix, dim=1)
n=size(matrix, dim=2)
WRITE(for(2:3),'(I2)')N
do i=1,N
write(*,Fmt=for)matrix(i,:)
end do
return
end subroutine
! 求解上三角矩阵:
subroutine upper(matrix)
implicit none
integer::m,n
real::matrix(:,:)
integer::i,j
real::e
m=size(matrix, dim=1)
n=size(matrix, dim=2)
do I=1,n-1
do j=i+1,m
e=matrix(j,i)/matrix(i,i)
matrix(j,i:m)=matrix(j,i:m)-matrix(i,i:m)*e
end do
end do
return
end subroutine
! 求解下三角矩阵:
subroutine lower(matrix)
implicit none
integer::m,n
real::matrix(:,:)
integer::i,j
real::e
m=size(matrix, dim=1)
n=size(matrix, dim=2)
do I=n,2,-1
do j=i-1,1,-1
e=matrix(j,i)/matrix(i,i)
matrix(j,1:i)=matrix(j,1:i)-matrix(i,1:i)*e
end do
end do
return
end subroutine
! 输出1:供gauss——jordan使用
subroutine output1(m,s)
implicit none
real::m(:,:),s(:)
integer i,j,n
n=size(m, dim=1)
do i=1,n
write(*,"(1x,f5.2,a1)",advance="no")m(i,1),'a'
do j=2,n
if(m(i,j)<0)then
write(*,"('-',f5.2,a1)",advance="no")-m(i,j),char(64+j)
else
write(*,"('+',f5.2,a1)",advance="no")m(i,j),char(64+j)
end if
end do
end do
end subroutine
! 求解上三角矩阵1
subroutine upper1(matrix,s,n)
implicit none
integer::n
real::matrix(n,n)
real::s(n)
integer::i,j
real::e
do I=1,n-1
do j=i+1,n
e=matrix(j,i)/matrix(i,i)
matrix(j,i:n)=matrix(j,i:n)-matrix(i,i:n)*e
s(j)=s(j)-s(i)*e
end do
end do
return
end subroutine
! 求解下三角矩阵1:
subroutine lower1(matrix,s,n)
implicit none
integer::n
real::matrix(:,:)
real::s(n)
integer::i,j
real::e
do I=n,2,-1
do j=i-1,1,-1
e=matrix(j,i)/matrix(i,i)
matrix(j,1:n)=matrix(j,1:n)-matrix(i,1:n)*e
s(j)=s(j)-s(i)*e
end do
write(*,"('=',f8.4)")s(i)
end do
return
end subroutine
end module
program main
use LinearAlgebra
implicit none
INTEGER,PARAMETER::n=3
real::a(n,n),b(n,n)
real::a1(n,n),s(n),ans(n)
integer i
data a / 1,2,1,3,2,3,2,3,4 /
data a1 / 1,2,3,4,5,6,7,8,8 /
data s / 12,15,17 /
write(*,*)"equation"
CALl output1(a,s)
call Gauss_Jordan(a,s,ans)
write(*,*)"ans="
do i=1,n
write(*,"(1x,a1,'=',f8.4)")char(64+i),ans(i)
end do
write(*,*)"matrix:"
call output(a)
call inverse(a,b)
write(*,*)"inverse"
call output(b)
write(*,*)"Matrix A:"
CALL output(a)
b=a
write(*,*)"Upper:"
CALL upper(b)
CALL output(b)
b=a
write(*,*)"lower:"
CALL upper(b)
CALL output(b)
write(*,"('det(A)=',F6.2)")Determinant(a)
stop "over"
end program