2016-06-12 12 views
0

私は文字と実数の両方を含む行列を持っています。この行列を読み込むプログラムが必要です(それ自体で次元を見つける)。私の行列の次元のために私が得たこのコード(3,2)で行列の次元を見つけるには?

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

! 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 

はここに私の行列である:ここに私のコードです。

+1

あなたのコードは、実際には3つの行数を数えます。 mは1に初期化され、iostatエラー(単にファイルの終わりである)にかかわらず2番目のループでインクリメントされるため、mに対して2が得られます。ちょっとしたことですが、あなたのopenステートメントでiostatを指定してから、値をチェックすることは何もしません。 – agentp

+0

ファイルを開く前にファイルの内容について何を知っていますか?それは常に2つの(別々の)1文字の要素の後に3つの(数字の、実数の)要素が続く 'n '(未知の)行で構成されていますか? –

+0

@ High Performance Mark我々は行列に文字と整数の両方が含まれていることを知っています。文字列とm列の整数を含むn列を持つことがあります。 –

答えて

1

サンプルコードにはいくつかのエラーがあります。つまり、私のためにはコンパイルされませんが、いくつかの変更が加えられた後も同様の結果が得られます。 * 更新:@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が非ゼロになるとすぐにブロックを終了しないことに注意してください。一度ブロックの最後に達すると、ブロックが終了します。その後、次の読み込みがファイルの先頭から始まるように、ファイルを巻き戻す必要があります。あなたはむしろあなたが本当にこれはその後、ここ

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 
+1

あなたの2つの答えは、別々の回答になるには十分に違いますか?単に回答を修正/改善する場合は、新しい回答を投稿するのではなく、編集する必要があります。ここの2つはほぼ同じように見えるので、古いものを削除してください。 – agentp

+0

@agentpありがとう、私はここで何が適切であるか分からなかった、私は重要な違いのいくつかの定義のために、それが重要な違いをもたらすならば、答えを修正することに対する議論を聞いた。 –

+0

@roygivbありがとう私はちょうど編集中にそれを見つけた!私はそれが間違っているので、私は元の答えを削除する必要がありますと思う。このバージョンは(うまくいけば)正しくなければならず、元の投稿からの主なポイントを含めるように編集しました。 –

1

ようなもので二doループを置き換えないようにしたい場合はmaxElementを指定する必要がないだろうと述べた以前のコメントで

は/ 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 
関連する問題