Matrix 如何求矩阵的维数?

Matrix 如何求矩阵的维数?,matrix,fortran,dimension,Matrix,Fortran,Dimension,我有一个包含字符和实数的矩阵,我想要一个程序来读取这个矩阵(自己查找维度)。这是我的密码: ! A fortran95 program for G95 Program Project2nd implicit none character(len=40), allocatable :: a(:,:) integer i,j,k,n,m,l,st character(len=40) d n=0; m=1; j=1; open(10,file=& '/Users/dariakowsari/

我有一个包含字符和实数的矩阵,我想要一个程序来读取这个矩阵(自己查找维度)。这是我的密码:

! A fortran95 program for G95
Program Project2nd
implicit none
character(len=40), allocatable :: a(:,:)
integer i,j,k,n,m,l,st
character(len=40) d
n=0; m=1; j=1;

open(10,file=&
 '/Users/dariakowsari/Documents/Physics/Programming/Fortran95-Projects/Project2nd/input.txt', &
   IOstat=st)

do while (st == 0)
   read(10,*,IOstat=st) d
   n=n+1
end do

st=0
do j=1,m
  do while (st == 0)
     allocate(a(1,m))
        read(10,*,IOstat=st) (a(1,j),j=1,m)
          m=m+1
         deallocate(a)
 end do

 print*, n,m


end
这是我的矩阵:

a   b   13   15.5   13.2
c   d   16   16.75  19
e   f   19.2 12.2   18.2

通过这段代码,我得到了矩阵维数的(3,2)。

您的示例代码中有一些错误,这意味着它不能为我编译,但经过一些更改后,我设法得到了与您类似的结果。 *更新:正如@francescalus在对我的另一个(现已删除)答案的评论中所指出的,这种方法涉及未定义的行为,因此不是一个合适的解决方案。这是因为试图从文件中读取的元素比当前的多。)

这里有一种替代方法,可以避免这种未定义的行为,但可能效率很低

Program Project2nd
  implicit none
  character(len=40), allocatable :: a(:)
  integer, allocatable :: ind(:)
  integer, parameter :: maxElements = 100
  integer i,j,n,m,st
  character(len=40) d
  n=0;

  open(10,file='mat.txt',IOstat=st)
  !Find number of lines
  do while (st == 0)
     read(10,*,IOstat=st) d
     if(st ==0) n=n+1
  end do
  !Move back to the start of the file
  rewind(10)

  !Read all of the data
  do m=n,maxElements,n
     allocate(a(m))
     read(10,*,IOstat=st) a
     deallocate(a)
     rewind(10)
     if(st.ne.0) exit
  enddo
  m = m -n !Need to roll back m by one iteration to get the last which worked.
  if(mod(m,n).ne.0) then
     print*,"Error: Number of elements not divisible by number of rows."
     stop
  endif
  !Number of columns = n_elements/nrow
  m=m/n
  print*, n,m
end Program Project2nd
本质上,这使用了与计算行数相同的代码,但是请注意,只有在读取成功时(即st==0),才需要增加n。注意,st变为非零时,我们不会立即退出While块,只有在到达While块的末尾时才会退出。之后,我们需要倒带文件,以便下一次读取从文件的开头开始

在前面的评论中,您提到,如果确实希望避免这种情况,则不必指定
maxElement
,然后将第二个
do
循环替换为

  st = 0 ; m = n
  do while (st==0)
     allocate(a(m))
     read(10,*,IOstat=st) a
     deallocate(a)
     rewind(10)
     if(st.ne.0) then
       m = m - n !Go back to value of m that worked            
       exit
     endif
     m=m+n
  enddo

您的示例代码中有一些错误,这意味着它不能为我编译,但经过一些更改后,我设法得到了与您类似的结果。 *更新:正如@francescalus在对我的另一个(现已删除)答案的评论中所指出的,这种方法涉及未定义的行为,因此不是一个合适的解决方案。这是因为试图从文件中读取的元素比当前的多。)

这里有一种替代方法,可以避免这种未定义的行为,但可能效率很低

Program Project2nd
  implicit none
  character(len=40), allocatable :: a(:)
  integer, allocatable :: ind(:)
  integer, parameter :: maxElements = 100
  integer i,j,n,m,st
  character(len=40) d
  n=0;

  open(10,file='mat.txt',IOstat=st)
  !Find number of lines
  do while (st == 0)
     read(10,*,IOstat=st) d
     if(st ==0) n=n+1
  end do
  !Move back to the start of the file
  rewind(10)

  !Read all of the data
  do m=n,maxElements,n
     allocate(a(m))
     read(10,*,IOstat=st) a
     deallocate(a)
     rewind(10)
     if(st.ne.0) exit
  enddo
  m = m -n !Need to roll back m by one iteration to get the last which worked.
  if(mod(m,n).ne.0) then
     print*,"Error: Number of elements not divisible by number of rows."
     stop
  endif
  !Number of columns = n_elements/nrow
  m=m/n
  print*, n,m
end Program Project2nd
本质上,这使用了与计算行数相同的代码,但是请注意,只有在读取成功时(即st==0),才需要增加n。注意,st变为非零时,我们不会立即退出While块,只有在到达While块的末尾时才会退出。之后,我们需要倒带文件,以便下一次读取从文件的开头开始

在前面的评论中,您提到,如果确实希望避免这种情况,则不必指定
maxElement
,然后将第二个
do
循环替换为

  st = 0 ; m = n
  do while (st==0)
     allocate(a(m))
     read(10,*,IOstat=st) a
     deallocate(a)
     rewind(10)
     if(st.ne.0) then
       m = m - n !Go back to value of m that worked            
       exit
     endif
     m=m+n
  enddo

下面是如何进行w/o倒带

  implicit none
  character(len=100) wholeline
  character(len=20), allocatable :: c(:)
  integer iline,io,ni,nums
  open(20,file='testin.dat')
  iline=0
  do while(.true.)
     read(20,'(a)',iostat=io)wholeline
     if(io.ne.0)exit
     iline=iline+1
     ni=lineitems(wholeline)
     allocate(c(ni))
     read(wholeline,*)c
     nums=ctnums(c)
     write(*,*)'line',iline,' contains ',ni,'items',nums,
 $        'are numbers'
     deallocate(c)
  enddo
  write(*,*)'total lines is ',iline
  contains

  integer function ctnums(c)
  ! count the number of items in a character array that are numbers
  ! this is a template,
  ! obviously you could assign the numbers to a real array here
  character(len=*), allocatable :: c(:)      
  real f
  integer i,io
  ctnums=0
  do i = 1,size(c)
     read(c(i),*,iostat=io)f
     if(io.eq.0)ctnums=ctnums+1
  enddo
  end function

  integer function lineitems(line)
  ! count the number of items in a space delimited string
  integer,parameter ::maxitems=100
  character(len=*) line
  character(len=80) :: c(maxitems)
  integer iline,io
  lineitems=0
  do iline=1,maxitems
     read(line,*,iostat=io)c(:iline)
     if(io.ne.0)return
     lineitems=iline
  enddo
  if(lineitems.eq.maxitems)write(*,*)'warning maxitems reached'
  end function
  end
输出

line 1 contains 5 items 3 are numbers
line 2 contains 5 items 3 are numbers
total lines is 2

下面是如何进行w/o倒带

  implicit none
  character(len=100) wholeline
  character(len=20), allocatable :: c(:)
  integer iline,io,ni,nums
  open(20,file='testin.dat')
  iline=0
  do while(.true.)
     read(20,'(a)',iostat=io)wholeline
     if(io.ne.0)exit
     iline=iline+1
     ni=lineitems(wholeline)
     allocate(c(ni))
     read(wholeline,*)c
     nums=ctnums(c)
     write(*,*)'line',iline,' contains ',ni,'items',nums,
 $        'are numbers'
     deallocate(c)
  enddo
  write(*,*)'total lines is ',iline
  contains

  integer function ctnums(c)
  ! count the number of items in a character array that are numbers
  ! this is a template,
  ! obviously you could assign the numbers to a real array here
  character(len=*), allocatable :: c(:)      
  real f
  integer i,io
  ctnums=0
  do i = 1,size(c)
     read(c(i),*,iostat=io)f
     if(io.eq.0)ctnums=ctnums+1
  enddo
  end function

  integer function lineitems(line)
  ! count the number of items in a space delimited string
  integer,parameter ::maxitems=100
  character(len=*) line
  character(len=80) :: c(maxitems)
  integer iline,io
  lineitems=0
  do iline=1,maxitems
     read(line,*,iostat=io)c(:iline)
     if(io.ne.0)return
     lineitems=iline
  enddo
  if(lineitems.eq.maxitems)write(*,*)'warning maxitems reached'
  end function
  end
输出

line 1 contains 5 items 3 are numbers
line 2 contains 5 items 3 are numbers
total lines is 2


您的代码实际上只计算三行。只因为m被初始化为1,并且在第二个循环中无论iostat错误是什么(这只是文件的结尾),都会递增,所以m才得到2。有点旁白,但在open语句中指定iostat,然后不检查值是一种糟糕的做法。在打开文件之前,您对文件的内容了解多少?它是否总是由
n
(未知)行组成,每行有2个(单独的)单字符元素,后跟3个(数字、实数)元素?@高性能标记我们知道矩阵同时包含字符和整数。它可能有n列包含字符,m列包含整数。第一个循环到达文件的末尾。(我猜你没有意识到,即使你只读取了一项,读取也会前进到下一行)之后的所有读取都会给iostat带来文件结束错误。无论是否出现iostat错误,行
m=m+1
的执行都是相同的。我是否应该使用倒带以使其从文件的第一行读取?您的代码实际上只计算三行。只因为m被初始化为1,并且在第二个循环中无论iostat错误是什么(这只是文件的结尾),都会递增,所以m才得到2。有点旁白,但在open语句中指定iostat,然后不检查值是一种糟糕的做法。在打开文件之前,您对文件的内容了解多少?它是否总是由
n
(未知)行组成,每行有2个(单独的)单字符元素,后跟3个(数字、实数)元素?@高性能标记我们知道矩阵同时包含字符和整数。它可能有n列包含字符,m列包含整数。第一个循环到达文件的末尾。(我猜你没有意识到,即使你只读取了一项,读取也会前进到下一行)之后的所有读取都会给iostat带来文件结束错误。无论是否出现iostat错误,行
m=m+1
的执行都是相同的。我是否应该使用倒带,以便从文件的第一个部分读取?您的两个答案是否足够不同,可以成为单独的答案?如果您只是在修改/改进答案,您应该对其进行编辑,而不是发布新答案。这里的两个看起来几乎一样,所以你应该删除旧的一个。@agentp谢谢,我不确定这里什么是合适的,我听到过反对修改答案的论点,如果它引入了显著的差异,对于一些重要的定义。@roygivb谢谢,我刚刚在编辑时发现了这一点!我想我应该删除原来的答案,因为它是不正确的。这个版本应该(希望)是正确的,我已经编辑过,包含了原始帖子的要点。非常感谢@d_1999。你的答案正是我想要的。请注意,我之所以选择以
n
的步骤进行迭代,是因为@SinaTehrani表示他们可能对一些相当大的矩阵感兴趣,所以我认为这种优化(将迭代次数减少一个因子
n
)是w