Matrix 用Fortran中的ZGETRI求逆矩阵
我试图用ZGETRI计算复矩阵的逆,但是 即使执行时没有错误(info=0), 它没有给我正确的逆矩阵,我有绝对的 不知道错误来自哪里Matrix 用Fortran中的ZGETRI求逆矩阵,matrix,fortran,lapack,intel-fortran,Matrix,Fortran,Lapack,Intel Fortran,我试图用ZGETRI计算复矩阵的逆,但是 即使执行时没有错误(info=0), 它没有给我正确的逆矩阵,我有绝对的 不知道错误来自哪里 PROGRAM solvelinear implicit none INTEGER :: i,j,info,lwork INTEGER,dimension(3) :: ipiv COMPLEX(16), dimension(3,3) :: C,Cinv,M,LU COMPLEX(16),allocata
PROGRAM solvelinear
implicit none
INTEGER :: i,j,info,lwork
INTEGER,dimension(3) :: ipiv
COMPLEX(16), dimension(3,3) :: C,Cinv,M,LU
COMPLEX(16),allocatable :: work(:)
info=0
lwork=100
allocate(work(lwork))
ipiv=0
work=(0.d0,0.d0)
C(1,1)=(0.d0,-1.d0)
C(1,2)=(1.d0,5.d0)
C(1,3)=(2.d0,-2.d0)
C(2,1)=(4.d0,-1.d0)
C(2,2)=(2.d0,-3.d0)
C(2,3)=(-1.d0,2.d0)
C(3,1)=(1.d0,0.d0)
C(3,2)=(3.d0,-2.d0)
C(3,3)=(0.d0,1.d0)
write(*,*)"C = "
do i=1,3
write(*,10)(C(i,j),j=1,3)
end do
!-- LU factorisation
LU=C
CALL ZGETRF(3,3,LU,3,ipiv,info)
write(*,*)'info = ',info
write(*,*)"LU = "
do i=1,3
write(*,10)(LU(i,j),j=1,3)
end do
!-- Inversion of matrix C using the LU
Cinv=LU
CALL ZGETRI(3,Cinv,3,ipiv,work,lwork,info)
write(*,*)'info = ',info
write(*,*)"Cinv = "
do i=1,3
write(*,10)(Cinv(i,j),j=1,3)
end do
!-- computation of C^-1 * C to check the inverse
M = matmul(Cinv,C)
write(*,*)"M = "
do i=1,3
write(*,10)(M(i,j),j=1,3)
end do
10 FORMAT(3('(',F20.10,',',F20.10,') '))
END PROGRAM solvelinear
我用ifort编译(我的LAPACK
libraries版本3.7.1也用ifort编译)。生成文件:
#$Id: Makefile $
.SUFFIXES: .f90 .f .c .o
FC = ifort
FFLAGS = -g -check all -zmuldefs -i8
LIBS = -L/path/to/lapack-3.7.1 -llapack -ltmglib -lrefblas
MAIN = prog.o
EXEC = xx
all: ${MAIN} Makefile
${FC} ${FFLAGS} -o ${EXEC} ${MAIN} ${LIBS}
.f.o: ${MODS} Makefile
${FC} ${FFLAGS} -c $<
.f90.o: ${MODS} Makefile
${FC} ${FFLAGS} -c $<
如果我没弄错的话,M应该是身份。我建议你不要使用像
REAL(4)
或COMPLEX(16)
这样的文字数字表示法
首先,它很难看,不便于携带
第二,对于复杂的变量,它可能会令人困惑
在这里,您将变量定义为COMPLEX(16)
,但ZGETRI
,以及所有其他LAPACKZ
例程需要COMPLEX*16
。这些是不一样的
COMPLEX*16
是包含REAL*8
组件的复数的非标准表示法REAL*8
是8字节实数的非标准表示法,通常相当于双精度
COMPLEX(16)
是一个包含两个REAL(16)
组件的复数,前提是存在此类组件。在提供REAL(16)
的编译器中,此REAL是四倍精度,而不是双精度
因此,您实际上是在传递32字节的复杂变量,而不是16字节的复杂变量
有足够的资源学习如何正确使用Fortran。你可以从
integer, parameter :: dp = kind(1.d0)
及
请不要像以前那样将标签放在括号中的标题中。StackOverflow有一个丰富的标签系统,将标签放在它们所属的问题下面。如果它们是标题不可分割的一部分,它们可以留在那里(如“in-Fortran”或“in-a-Fortran function”或类似),但不要只在那里列出标签列表,标签列表就在问题的下方。我想知道“最佳”方法是否是使用复数*16而不是复数(种类(1.0d0))来匹配原始源代码中使用的类型,但我不确定它在参考(或最新版本或mkl或…)库中是如何定义的。我在回答中提到了这一点,但我不推荐这种方式,因为它不是(标准)Fortran。@roygvib复杂*16的主要原因是因为没有标准的双复杂度,但DGETRF使用双精度,因此,我建议使用
kind(1.d0)
。感谢您提供的信息,是的,我同意kind(1.d0)实际上是最好的(我使用它)。我担心的是,如果默认实数设置为64位(通过编译器选项或其他方式),将来可能会出现问题。。。(从这个意义上讲,来自iso_fortran_env的complex(real64)可能更安全)。但在此之前,Lapack本身以混合方式使用1.0D0和复数*16(或实数*8),因此混乱。。。哈哈(但这只是一个非常小的问题,所以我也认为复杂(种类(0.d0))是最实用的。)@B_runo不完全是这样。编译器确实具有四倍精度,但四倍精度与Z
例程(如ZGETRF
)不兼容。它们需要双重精度。
integer, parameter :: dp = kind(1.d0)
real(dp) :: x
complex(dp) :: c