반응형

     정보

    • 업무명     : 포트란을 활용한 배열 : 개요, 정합성 요구, 배열 작성자 (constructor), 마스크된 배열 할당 (where문), 동적배열, 배열함수

    • 작성자     : 이상호

    • 작성일     : 2020-11-26

    • 설   명      :

    • 수정이력 :

     

     내용

    [개요]

    • 안녕하세요? 웹 개발 및 연구 개발을 담당하고 있는 해솔입니다.

    • Fortran (포트란)은 수식 (Formular) 변환기 (Translator)의 약자로 과학 계산용으로 주고 사용되는 언어입니다.

    • 복잡한 계산 수행 성능이 뛰어나 공학과 자연과학 등 특정분야에 주로 사용되며 기상 데이터 처리를 위해 널리 사용되고 있습니다.

    • 오늘 포스팅은 포트란을 활용한 배열을 소개합니다.

     

     

    [특징]

    • 기상 데이터 처리를 위해서 포트란 (Fortran)기술이 요구되며 이 프로그램은 이러한 목적을 달성하기 위한 기술서

     

    [기능]

    • 개 요

    • 정합성 요구

    • 배열 작성자 (constructor)

    • 마스크된 배열 할당 (where문)

    • 동적배열

    • 배열함수

     

    [활용 자료]

    • 없음

     

    [자료 처리 방안 및 활용 분석 기법]

    • 없음

     

    [사용법]

    • 없음

     

    [사용 OS]

    • Linux (CentOS v7.8)

     

    [사용 언어]

    • gfortran v4.8.5

     

     세부 내용

    개요
    • 프로그램을 개발하는 이유 중 하나는 많은 양의 데이터를 동일한 방법으로 빠르게 처리하기 쉽게 하기 위한 위함이 있습니다.

    • 예를 들면 수 많은 숫자 세트들 중 평균 값을 찾기 위해, 또는 방대한 양의 숫자 또는 이름 목록을 정렬하기 위하여, 또는 많은 학생들의 시험 결과를 분석하는 등 입니다.

    • 이러한 데이터를 처리 하기 위하여 우리는 배열을 이용할 수 있습니다.

    • 배열은 하나의 이름으로 참조할 수 있는 같은 타입의 변수나 상수의 집합이라고 할 수 있습니다.

    • 이 집합은 메모리 상에서 연속적인 위치를 점유하게 됩니다.

    • 연속적인 위치에 있기에 같은 반복적인 연산은 DO문을 이용하여 수 많은 데이터에 적용 할 수 있습니다.

    • 혹은 특정 조건에 해당하는 경우만 WHERE문을 통해 계산 할 수 있습니다.

    • 포트란에서는 조건만 만족한다면 배열끼리 연산도 가능합니다.

    • 배열을 사용할 때 기본적인 다음 사항을 지키는 습관이 중요합니다.

      • 배열 사용 전 에는 반드시 초기화

        • 초기화를 하지 않을 경우 쓰레기(의도치 않은)값이 저장되어 잘못된 계산을 유발합니다.

           

      • 배열 크기를 파라미터를 이용하여 선언하라

        • 배열 크기를 항상 유의 해야 합니다. 의도했던 크기보다 넘어갈 경우 에러가 발생하거나 위와 비슷한 상황이 발생합니다.

     

    정합성 요구
    • 포트란에서는 반드시 스칼라로 제한되어 사용되는 소수의 연산을 제외하고는 어떤 연산도 배열을 피연산수로 가질 수 있으며 그 결과도 배열이 될 수 있습니다.

    • 거의 모든 표현에 배열을 직접 사용할 수 있도록 함으로써 데이터 병렬을 지원하고 있습니다.

    REAL, DIMENSION(100) :: a, b 
    a=2.0 
    b=b*a

     

    • 배열 연산에서의 정합성 요구는 연산에 참여하는 배열들의 모양이 서로 일치해야 함을 의미합니다. 

    • 배열 연산에서 사용되는 피연산수 즉 배열은 서로 같은 차원을 가져야 하며 각 차원마다 원소의 개수가 같아야 한다는 것 입니다.

    • 물론 연산의 결과 역시 연산에 참여한 배열들과 같은 모양을 가지게 될 것입니다.

    • 간단하게 수학에서 배운 행렬연산을 생각하시면 이해가 쉬울 듯 합니다.

     

     

    • 이와 같은 연산의 정의로 인해 연산에 참여하는 각 배열의 모양이 같아야 한다는 정합성 요구를 이해할

      수 있습니다. 

    • 그러나 한가지 예외 사항이 있는데 피연산수 중 하나로 스칼라가 올 때입니다. 배열 B에 대해 B+2는 유효한 연산입니다.

     

     

    배열 작성자 (constructor)

    [암시적 DO 구문]

    • 포트란에서는 1차원 배열을 명시적으로 구성 하기 위하여 배열 작성자(array constructor)를 이용할수 있습니다. 

    • 배열 작성자는 (/1, 2, 3, 4/)와 같이 (/…/)내에 콤마로 배열의 원소를 구분해 나열하는 것을 말합니다. 

    • 일반적으로 배열 작성자의 각 원소는 어떤 스칼라 표현도 가능합니다.

    • 스칼라 표현과 더불어 배열 작성자의 원소를 나타내는 방법으로 암시적 DO구문과 배열표현이 있습니다.

    • 암시적 DO 구문은 다음과 같은 형식을 가집니다.

    (/ expression-list, index-variable=first-value, last-value[,increment]/)

     

    • 표현식 (/(k, k=1,n)/)는 원소가 1,2,3, …,n으로 주어지는 1차원 벡터를 생성하며 n=4 이면 (/1,2,3,4/)가 됩니다.

    (/1,0,1,0,1,...../) = (/(1,0, j=1,500000)/) ! 1과 0이 반복되는 100만개의 원소로 구성 되는 벡터
    (/ ((i + j, i = 1, 3), j = 1, 2) /) ! = (/ 2, 3, 4, 3, 4, 5 /) ! 암시적 DO 구문을 대응되는 스칼라 표현

     

    [배열표현]

    • 배열 표현은 임의 차원의 배열을 이용해 배열 작성자를 구성하는 것입니다.

    • 배열 A 가 1000ⅹ1000의 2차원 배열일 때 (/A+1.3/)은 100만개의 원소를 가지는 배열 작성자가 됩니다.

    • 각 원소는 배열 A의 각 원소에 1.3을 더한 값이 되며, 1열 1000개, 2 열 1000개, … 와 같이 열-우선 순으로 나열돼 하나의 배열 작성자를 구성합니다.

    (/A+1.3/) = (/ ( ( A(j,k)+1.3, j=1,1000 ), k=1,1000 ) /)

     

    • 여기서 A+1.3의 원소를 열-우선 순으로 나열하지 않고 행-우선 순으로 나열된 배열 작성자를 원한다면다음과 같이 암시적 DO구문을 이용합니다.

    (/ ( ( A(j,k)+1.3, k=1,1000 ), j=1,1000 ) /)

     

    [RESHAPE 함수]

    • 1차원으로 정의되는 배열 작성자를 이용해 원하는 모양의 배열을 구성하기 위해서 내부함수 RESHAPE를 사용할 수 있습니다. RESHAPE 함수는 다음과 같은 형태로 사용합니다.

    RESHAPE (array-constructor, shape-vector)

     

    • shape-vector는 원하는 배열 모양에 대한 각 차원의 크기를 지정하는 값을 (/ …/)로 묶어 나타냅니다.

    REAL, DIMENSION (3,2) :: ra 
    ra = RESHAPE((/ ((i+j,i=1,3),j=1,2)/), SHAPE=(/3,2/))

     

    • 다음은 1000ⅹ1000크기의 실수타입 단위 행렬을 배열 작성자와 RESHAPE 함수를 이용해 Ident_1000이라는 이름을 가지는 배열 상수로 정의한 것입니다.

    REAL, PARAMETER, DIMENSION(1000,1000) :: Ident_1000 = & 
    RESHAPE( ( /(1.0,(0.0,k=1,1000),j=1,999),1.0/ ), (/1000,1000/))

     

    마스크된 배열 할당 (where문)

    [WHERE 문]

    • 마스크(mask)란 배열자료값을 이용한 논리형 표현식으로 마스크된 배열 연산은 배열의 각 원소에 병렬로 수행되는 연산이 일부 원소에만 적용되도록 logical 타입의 마스크를 사용하는 것입니다.

    • 마스크를 통하여 배열에 값을 할당하기 위해 WHERE 문을 사용합니다.

    WHERE (mask) array-assignment-statement

     

    • WHERE 구문의 마스크 원소가 .TRUE.일 때 이에 대응되는 배열 원소에 값이 할당 되며, .FALSE.가 되면 값이 할당되지 않습니다.

    • 다음은 마스크를 이용해 배열의 일부 원소에 값을 할당하는 예제 입니다.

    WHERE (C .NE. 0) A = B/C
    

     

    • 여러 개의 할당에 하나의 마스크를 적용할 수 있으며 이때 WHERE 문은 다음과 같이 블록화 됩니다.

    WHERE (mask) 
    array-assignment-1 
    array-assignment-2 
    ......... 
    END WHERE
    

     

    • 또한 블록화된 WHERE 문에 ELSE WHERE 옵션을 덧붙여 사용하면 마스크 원소가 .FALSE.일 때도 배열에 값을 할당하도록 할 수 있습니다.

    WHERE (C .NE. 0) 
    A = B/C 
    ELSE WHERE 
    A = B 
    END WHERE

     

    동적배열

    [Automatic Array]

    • 포트란이 지원하는 동적 배열은 프로그램 실행 중에 메모리가 할당되며 배열의 크기를 프로그램에서 계산되는 값 또는 입력 값으로 결정할 수 있습니다.

    • 동적 배열은 automatic array, allocatable array, 그리고 pointer array 이렇게 세 가지 형태가 있습니다.

    • Automatic array는 크기가 dummy 인수에 의해 결정되는 지역 배열입니다.

    • 프로시저 내에서 자동 생성되고 프로시저의 종료와 함께 자동으로 소멸됩니다.

    • 크기가 프로시저의 dummy 인수에 의해 결정되므로 프로시저가 호출될 때 마다 그 크기는 달라 질 수 있습니다.

    • 다음 예에서 배열 work1 과 work2 는 automatic array의 예입니다.

    SUBROUTINE sub(n, a) 
      IMPLICIT NONE 
      INTEGER :: n 
      REAL, DIMENSION(n, n) :: a 
      REAL, DIMENSION (n, n) :: work1 
      REAL, DIMENSION (SIZE(a, 1)) :: work2 
    END SUBROUTINE sub

     

    [Allocatable Arrays]

    • 포트란에서는 ALLOCATE 문을 이용해 메모리를 동적으로 할당할 수 있습니다.

    • Allocatable array 는 다음과 같이 ALLOCATABLE attribute 로 선언하여 사용합니다.

    PROGRAM simulate 
      IMPLICIT NONE 
      INTEGER :: n 
      INTEGER, DIMENSION(:,:), ALLOCATABLE :: a 
    END PROGRAM simulate

     

    • 배열의 이름과 차원은 위와 같이 미리 결정되어 있어야 하지만 그 크기는 다음과 같이 입력 값으로부터받아오거나 프로그램 실행 중에 계산되는 값에 의해 결정됩니다.

    PRINT *,'Enter n:' 
    READ *,n 
    IF(.NOT.ALLOCATED(a)) ALLOCATE( a(n,2*n) ) 
    ........ 
    DEALLOCATE(a)
    

     

    • Allocatable array 는 프로시저 내에서 지역적으로 사용될 수도 있고 프로그램 전체에서 global 하게 사용될 수도 있습니다.

    • allocatable array를 더 이상 사용할 필요가 없다면 DEALLOCATE 문을 이용해 해제 시켜야 합니다. 

    • 그렇지만 , 프로시저 내에서 지역적으로 사용된 allocatable array는 SAVE로 명시해 두지 않은 경우 프로시저의 종료와 함께 자동으로 소멸됩니다.

     

    [Pointer Arrays]

    • pointer array는 ALLOCATE 문을 이용해 명시적으로 할당되고 실행 중에 결정되는 크기를 가지며DEALLOCATE 문을 이용해 명시적으로 할당 해제 된다는 점에서 allocatable array와 유사합니다.

    • pointer array는 target으로 명시적으로 선언된 다른 배열과 배열 부분에 대한 aliasing 을 위해 사용됩니다.

    REAL, TARGET :: B(100,100) ! 배열 B 는 target 속성을 가진다 . 
    REAL, POINTER :: U(:,:),V(:),W(:,:) ! 3 개의 포인터 배열 선언
    ... 
    U => B(I:I+2,J:J+2) ! U 는 B 의 3X3 부분을 point 
    ALLOCATE ( W(M,N) ) ! 크기가 MXN 인 W 를 동적할당
    V => B(:,J) ! V는 B 의 J 번째 열을 point 
    V => W(I-1,1:N:2) ! V는 W 의 I-1 번째 열의 일부를 point 하도록 바꿈
    

     

    • allocatable 로 선언하는 대신 포인터 로 선언

    • 다른 배열 또는 배열 부분으로의 대체(aliasing) 을 위해 사용

    • allocatable array의 모든 기능을 포함하지만 상대적으로 복잡하여 효율적인 면에서 좋지 않음

    • 지역적으로 계산되는 값에 의존하는 크기를 가지는 동적 배열의 정의를 위해 일반적으로 allocatable array를 많이 사용합니다.

    • 그러나 알고리즘에서 동적 대체(aliasing)가 필요한 경우에 pointer array를 사용하게 됩니다.

    • 관련하여 보다 자세한 내용은 포인터와 같이 다시 한번 이야기 하겠습니다.

     

     참고 문헌

     문의사항

    [기상학/프로그래밍 언어]

    • sangho.lee.1990@gmail.com

    [해양학/천문학/빅데이터]

    • saimang0804@gmail.com
    반응형
    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기