Fortran矩阵相乘(复矩阵、实矩阵)

ZuoZhihua
哈尔滨工程大学 船舶工程学院
2020/8/27 星期四 午 永新 ThinkPad E485 Windows Home
微信:zozha96

1 Fortran矩阵求逆、相乘模块

module operation_i

    !!// operator ".i." is used for solve the inverse MATRIX of a given MATRIX. 
    public
    interface operator(.i.) !!// 自定义重载矩阵求逆操作符
        module procedure brinv !!// 实矩阵求逆
        module procedure bcinv !!// 复矩阵求逆
    end interface
    private :: brinv, bcinv
contains
    !!// 实矩阵求逆核心代码 trans from 徐士良《Fortran常用算法集》
    !!// 作者:zuozhihua 时间:2020/8/18 地点:江西
    function brinv(re) result(r)
    
        real,intent(in) :: re(:,:) !!// 原矩阵
        real :: r(size(re,1),size(re,1)) !!// 逆矩阵
        integer :: flag,n !!// flag判断奇异性;n是矩阵维度
        real :: t,d !!// 中间变量
        integer :: is(size(re,1)),js(size(re,1)) !!// 中间变量
    
        n=size(re,1) !!// 获取矩阵维度
        r=re !!// 复制值
        flag=1
        do k=1,n
            d=0.0
            do i=k,n
                do j=k,n
                      if (abs(r(i,j)).gt.d) then
                        d=abs(r(i,j))
                        is(k)=i
                        js(k)=j
                      end if
                end do
            end do
            if (d+1.0.eq.1.0) then
                flag=0
                write(*,*) "flag=0,实矩阵奇异!" 
                return !!// 矩阵奇异,退出逆矩阵求解
            end if
            do j=1,n
                t=r(k,j)
                r(k,j)=r(is(k),j)
                r(is(k),j)=t
            end do
            do i=1,n
                t=r(i,k)
                r(i,k)=r(i,js(k))
                r(i,js(k))=t
            end do
            r(k,k)=1/r(k,k)
            do j=1,n
                if (j.ne.k) r(k,j)=r(k,j)*r(k,k)
            end do
            do i=1,n
                if (i.ne.k) then
                      do j=1,n
                        if (j.ne.k) r(i,j)=r(i,j)-r(i,k)*r(k,j)
                    end do
                end if
            end do
            do i=1,n
                if (i.ne.k) r(i,k)=-r(i,k)*r(k,k)
            end do
        end do
        do k=n,1,-1
            do j=1,n
                t=r(k,j)
                r(k,j)=r(js(k),j)
                r(js(k),j)=t
            end do
            do i=1,n
                t=r(i,k)
                r(i,k)=r(i,is(k))
                r(i,is(k))=t
            end do
        end do
    end function
    !!// 复矩阵求逆核心代码 trans from 徐士良《Fortran常用算法集》
    !!// 作者:zuozhihua 时间:2020/8/10 地点:江西
    function bcinv(cpx)
        complex,intent(in) :: cpx(:,:) !!// 原矩阵
        complex :: bcinv(size(cpx,1),size(cpx,2)) !!// 逆矩阵
        integer :: flag,n !!// flag判断奇异性;n是矩阵维度
        real :: ar(size(cpx,1),size(cpx,1)),ai(size(cpx,1),size(cpx,1)) !!// 实部矩阵ar;虚部矩阵ai
        real :: d,p,t,q,s,b !!// 中间变量
        integer :: is(size(cpx,1)),js(size(cpx,1)) !!// 中间变量
    
        n=size(cpx,1)
        forall(i=1:n,j=1:n)
            ar(i,j) = real(cpx(i,j));ai(i,j) = imag(cpx(i,j))
        end forall
        flag=1
        do k=1,n
            d=0.0
            do i=k,n
                do j=k,n
                    p=ar(i,j)*ar(i,j)+ai(i,j)*ai(i,j)
                    if(p.gt.d) then
                        d=p
                        is(k)=i
                        js(k)=j
                    end if
                end do
            end do
            if(d+1.0.eq.1.0) then
                flag=0
                write(*,*) "flag=0,复矩阵奇异!" 
                return !!// 矩阵奇异,退出逆矩阵求解
            end if
            do j=1,n
                t=ar(k,j)
                ar(k,j)=ar(is(k),j)
                ar(is(k),j)=t
                t=ai(k,j)
                ai(k,j)=ai(is(k),j)
                ai(is(k),j)=t
            end do
            do i=1,n
                t=ar(i,k)
                ar(i,k)=ar(i,js(k))
                ar(i,js(k))=t
                t=ai(i,k)
                ai(i,k)=ai(i,js(k))
                ai(i,js(k))=t
            end do
            ar(k,k)=ar(k,k)/d
            ai(k,k)=-ai(k,k)/d
            do j=1,n
                if(j.ne.k) then
                    p=ar(k,j)*ar(k,k)
                    q=ai(k,j)*ai(k,k)
                    s=(ar(k,j)+ai(k,j))*(ar(k,k)+ai(k,k))
                    ar(k,j)=p-q
                    ai(k,j)=s-p-q
                end if
            end do
            do i=1,n
                if(i.ne.k) then
                    do j=1,n
                        if (j.ne.k) then
                            p=ar(k,j)*ar(i,k)
                            q=ai(k,j)*ai(i,k)
                            s=(ar(k,j)+ai(k,j))*(ar(i,k)+ai(i,k))
                            t=p-q
                            b=s-p-q
                            ar(i,j)=ar(i,j)-t
                            ai(i,j)=ai(i,j)-b
                        end if
                    end do
                end if
            end do
            do i=1,n
                if (i.ne.k) then
                    p=ar(i,k)*ar(k,k)
                    q=ai(i,k)*ai(k,k)
                    s=(ar(i,k)+ai(i,k))*(ar(k,k)+ai(k,k))
                    ar(i,k)=q-p
                    ai(i,k)=p+q-s
                end if
            end do
        end do
        do k=n,1,-1
            do j=1,n
                t=ar(k,j)
                ar(k,j)=ar(js(k),j)
                ar(js(k),j)=t
                t=ai(k,j)
                ai(k,j)=ai(js(k),j)
                ai(js(k),j)=t
            end do
            do i=1,n
                t=ar(i,k)
                ar(i,k)=ar(i,is(k))
                ar(i,is(k))=t
                t=ai(i,k)
                ai(i,k)=ai(i,is(k))
                ai(i,is(k))=t
            end do
        end do
        forall(i=1:n,j=1:n)
            bcinv(i,j) = cmplx(ar(i,j),ai(i,j))
        end forall
    
    end function
end module
    
module operation_x
    !!// operator ".x." is used for the multiplicative operation between MATRIXS. 
    public
    interface operator(.x.) !!// 自定义重载矩阵相乘操作符
        module procedure rmut !!// 实矩阵相乘
        module procedure cmut !!// 复矩阵相乘
        module procedure rcmut !!// 实复矩阵相乘
        module procedure crmut !!// 实复矩阵相乘 
    end interface
    private :: rmut, cmut, rcmut, crmut
contains
    !!// real m1,m2
    function rmut(m1,m2) result(ret)
    
        real,intent(in) :: m1(:,:),m2(:,:)
        real :: ret(size(m1,1),size(m2,2))
    
        ret=matmul(m1,m2)
    
    end function

    !!// cmplx*16 m1,m2
    function cmut(m1,m2) result(ret)
    
        complex,intent(in) :: m1(:,:),m2(:,:)
        complex :: ret(size(m1,1),size(m2,2))
    
        ret=matmul(m1,m2)
    
    end function
    
    !!// cmplx*16 & real
    function rcmut(m1,m2) result(ret)
    
        real,intent(in) :: m1(:,:)
        complex,intent(in) :: m2(:,:)
        complex :: ret(size(m1,1),size(m2,2))
    
        ret=matmul(m1,m2)
    
    end function
    !!// real & cmplx*16
    function crmut(m1,m2) result(ret)
    
        real,intent(in) :: m2(:,:)
        complex,intent(in) :: m1(:,:)
        complex :: ret(size(m1,1),size(m2,2))
    
        ret=matmul(m1,m2)
    
    end function

end module

2 矩形相乘测试

program main

    use operation_x
    real :: rmat1(2,2),rmat2(2,2),rmat3(2,2)
    complex :: cmat1(2,2),cmat2(2,2),cmat3(2,2)

    rmat1=1; rmat2=2
    cmat1=(3,3); cmat2=(4,4); cmat2(2,2)=(3,7)

    rmat3=rmat1.x.rmat2; cmat3=cmat1.x.cmat2

    write(*,*) "原实矩阵:"
    write(*,"(2(4x,es10.3))") ((rmat1(i,j),j=1,2),i=1,2)
    write(*,"(2(4x,es10.3))") ((rmat2(i,j),j=1,2),i=1,2)
    write(*,*) "结果实矩阵:"
    write(*,"(2(4x,es10.3))") ((rmat3(i,j),j=1,2),i=1,2)

    write(*,*) "原复矩阵:"
    write(*,"(4(4x,es10.3))") ((cmat1(i,j),j=1,2),i=1,2)
    write(*,"(4(4x,es10.3))") ((cmat2(i,j),j=1,2),i=1,2)
    write(*,*) "结果复矩阵:"
    write(*,"(4(4x,es10.3))") ((cmat3(i,j),j=1,2),i=1,2)

    read(*,*)

end program

2.1 VsCode程序运行图

编译环境:GCC Fortran 10.0; VsCode 2020; Win10 Home Edition; ThinkPadE485.


Done

2.2 问题

本程序模块没有验证矩阵是否符合乘法计算条件,如果3×4的矩阵与5×6的矩阵使用本程序模块相乘,也会出现计算结果,但显然是不对的。
如果你想使用这个模块需要注意这一点。或者你可以对模块代码进行更改。
今天是2020/11/2日,有空会把这个问题解决掉。

本程序模块使用单精度,如需使用双精度,请自行调整。

祝好运!


References

[1] 徐士良,Fortran常用算法集。
[2] 白海波,Fortran程序设计权威指南。
[3] 左志华,Fortran复数矩阵求逆

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351