2017-11-12 1 views
0

일부 포트란 코드는 서브 루틴과 호출로 구성되어 있습니다. 정의 된 창 크기를 사용하여 행렬의 요소 평균을 계산합니다. 예를 들어, winsize = 2를 사용하여 (10,10) 배열에서 서브 루틴을 호출하면 (5,5) 배열을 반환합니다.Fortran의 "end program"문에서 분할 오류

이 코드는 다음과 같이 표시됩니다 :

SUBROUTINE avgwin(ts, sizelat,sizelon,winsize,size2,size3,ts_new) 
implicit none 
double precision, dimension(10,sizelat,sizelon) :: ts 
double precision, dimension(winsize,winsize) :: store 
double precision, dimension(10,size2,size3) :: ts_new 
double precision :: par,ave 
integer :: sizelat, sizelon,i,j,k,winsize,size2,size3 
integer :: A, B,p,m,numb 
A=0 
B=0 
par = 11 !Hypothetical value to be excluded 
do i=1,10 !Looping through time 
    do j=1,sizelat !Looping through latitude 
     if ((j+winsize) > sizelat) then !Checks if it will exceed bounds 
      exit !If it'll exceed, discard remaining cells 
     end if 
     do k=1,sizelon !Looping through longitude 
      if ((k+winsize)>sizelon) then 
       exit 
      end if 
      store = ts(i,j:j+winsize,k:k+winsize) !Gets the values for that window 
      where (store == par) store = -99 !Replaces masked with -99 
      ave = 0 
      numb = 0 !Variable to count 
      do p=1,winsize 
       do m=1,winsize 
        if (store(p,m)==-99) then !Evaluates if it's masked, i.e., =-99 
         ave = ave 
        else 
         ave = ave + store(p,m) !Sum of existent values 
         numb = numb +1 !Updates counting variable 
        end if 
       end do 
      end do 
      ave = ave/numb !Calculates the mean 
      ts_new(i,A,B) = ave 
      B=B+1 
     end do 
     B=0 
     A=A+1 
    end do 
A=0 
B=0 
end do 
END SUBROUTINE 

program testefor 
implicit none 
double precision, dimension(10,10,10) :: teste 
double precision, dimension(10,5,5) :: oi 
integer :: i,j,k 

do i=1,10 
    do j=1,10 
     do k=1,10 
     teste(i,j,k)=i 
     end do 
    end do 
end do 

CALL avgwin(teste,10,10,2,5,5,oi) 
print*, oi(1,5,5) 

end program testefor 

나는 그것을 실행 해요, 그러나 나는 세그먼트 오류를 ​​얻을. 놀랍게도, GDB를 사용하여 디버깅을 시도했지만 정확한 결과를 반환하지만 프로그램을 종료 할 때 segfaults를 반환합니다. gdb에서 얻은 결과는 아래에서 확인할 수 있습니다 :

Breakpoint 1, testefor() at testefor.f90:56 
56  do i=1,10 
(gdb) cont 
Continuing. 
    1.0000000000000000  

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000400f73 in testefor() at testefor.f90:67 
67 end program testefor 

따라서 프로그램은 올바른 (1,5,5) 요소 = 1.0을 반환하지만 다른 곳에서는 오류가 발생합니다.

누군가가 나를 식별하는 데 도움을 줄 수 있습니까? 감사합니다

답변

3

디버그 모드에서 프로그램을 컴파일하고 많은 디버그 스위치를 활성화하는 것이 도움이 될 수있는 한 가지. 내 경우

은 내가 gfortran 컴파일, 내가 사용 :

  1. -g 모든 컴파일러 경고
  2. -fcheck=all을 수 있도록 더 나은 스택 추적에 대한 디버그 기호를
  3. -Wall
  4. -fbacktrace을 포함하는 런타임 검사를 가능하게합니다 (프로그램을 느리게 만들지 만 디버깅 중에는 유용합니다).

이 런타임 검사는 즉시 오류를 발견 :

At line 21 of file teste.F 
Fortran runtime error: Array bound mismatch for dimension 1 of array 'store' (2/3) 

store의 크기는 (winsize, winsize)이지만 크기 (windsize+1, winsize+1)의 그것으로 배열을 복사합니다. Fortran에서 배열을 분할하면 (1:10)은 1에서 10까지입니다. (1:1+10) 인 경우 1에서 11로 이동하므로 그 크기는 11입니다.

런타임이없는 경우 배열 경계 검사 (이 경우 -fcheck=all에 의해 활성화 됨) 디버깅이 실제로 어렵고 모든 종류의 예상치 못한 동작이 발생할 수 있습니다.

gfortran과 다른 컴파일러를 사용하는 경우 스위치가 표준화되지 않았으므로 컴파일러에서 이러한 테스트를 전환하는 방법을 읽어야합니다.

2

이것은 귀하의 질문에 대한 답변 (본인은 이미 답변 했음)을 의미하지는 않지만 귀하에게 도움이되는 몇 가지 힌트입니다.

  1. 당신은 다차원 배열을 통해 루프, 당신은 항상 첫 번째 인덱스를 통해 가장 안쪽 루프를 가지고 있어야하고, 그래서

    ! Inefficient way to do it: 
    do i = 1, 10 
        do j = 1, 10 
         do k = 1, 10 
          a(i, j, k) = i*j+k 
         end do 
        end do 
    end do 
    
    !Efficient way to do it: 
    do k = 1, 10     ! <-+ 
        do j = 1, 10    ! | swapped 
         do i = 1, 10   ! <-+ 
          a(i, j, k) = i*j+k 
         end do 
        end do 
    end do 
    

    방법 포트란 저장 다차원 등 경우 배열은 첫 번째 인덱스가 가장 빠르게 변경됩니다.따라서 효율적인 방법은 연속적인 요소를 읽는 반면, 비효율적 인 방법은 메모리에서 상당히 뛰어 넘을 필요가 있습니다. 그래서 numb 당신의 값이 그냥 간단하게 numb=COUNT(store/=-99)로 계산 될 수 배열 .TRUE.

    • COUNT 카운트 인스턴스 대신이 복잡한 루프의

    • , 당신은 쉽게 SUMCOUNT을 사용할 수 있습니다

    • SUM에는 특정 값을 생략 할 수있는 선택적 인수 MASK이 있습니다. -99 아닌 모든 값을 요약하면, 당신은 사용할 수 있습니다 :

    s = SUM(store, MASK=(store /= -99)) 그래서 당신이 단지와 코드의 약 15 라인을 대체 할 수 :

    ave = sum(store, MASK=(store/=par))/count(store/=par) 
    
  2. 모두 storepardouble precision이다, 절대 값에 대한 부동 소수점 변수를 비교하는 것은 tricky

입니다.