수리수리연수리 코드얍

3. Fortran의 변수 체계(이론편) 본문

즐거운 Fortran

3. Fortran의 변수 체계(이론편)

ydduri 2023. 1. 29. 21:44
목차

1. 상수(Constants)

2. 변수(Variables)

1. 상수(Constants)

Fortran에서 처리할 수 있는 데이터로, 그 자료형에는 총 6가지 종류가 있다.

  • 정수형(integer): 1, 0, -512, -97, 2023
  • 실수형(real): 1.0, -0.12, 3.0E7(=\(3.0*10^7)\), 5.3E-1(=\(5.3*10^{-1})\)
  • 배정도형(double precision): 0.251209d0(=\(0.251209*10^0)\), 2.0D-1(=\(2.0*10^{-1})\), 1.0D99(=\(1.0*10^{99})\)
  • 복소수형(complex): (실수부, 허수부)순으로 작성, (2, -3)(=2-3$i$), (1.0, 9.9E-1)(=1.0+0.99$i$)
  • 논리형(logical)*: .TRUE., .FALSE.
  • 문자형(character): 'a', 'ABC', 'Fortran', 'Tutorial'

* 논리형의 TRUE, FALSE 앞뒤로 꼭 .(점)을 찍어주어야 한다! -> .TRUE. , .FALSE.

1) 지수 표기법

위의 상수 목록에서 실수형과 배정도형을 보면 모두 '소수*10의 n제곱' 형태의 '지수 표기법'을 따르고 있다는 것을 볼 수 있다. 따라서 Fortran에서 실수형과 배정도형을 자유자재로 사용하기 위해서는 지수 표기법에 익숙해질 필요가 있다.

지수 표기법이란 실수를 '소수*10의 n제곱' 형태로 표현하는 것으로, 이때 제곱 파트의 밑이 되는 숫자 10은 실수형에서는 E로, 배정도형에서는 D로 표기한다(Fortran은 대소문자 구분이 없으므로 e를 쓰나 E를 쓰나, d를 쓰나 D를 쓰나 상관없다). 여러 예시를 보면서 지수 표기법에 익숙해져 보자!

  • 1.23e7 = $1.23*10^7$
  • 5.0E-3 = $5.0*10^{-3}$
  • 2.20109D0 = $2.20109*10^0$
  • 9.7d-8 = $9.7*10^{-8}$

2) 실수형 vs 배정도형

실수형과 배정도형, 비슷해 보이는데 무엇이 다른걸까? 바로 '정밀도' 차이다. 배정도는 쉽게 말하면 ''를 갖는 형태라고 생각하면 된다. Fortran은 소수의 길이가 너무 길어지면 소수점 아래 어느 정도 자리수까지만 정확하게 표현하고 그 뒤의 숫자들은 이상하게 표기된다는 특징이 있는데, 이때 실수형이 아니라 배정도형을 쓰면 정확하게 표현되는 자리수가 더 늘어난다. 아래 예시를 보자.

real_constant라는 상수는 실수형, double_constant라는 상수는 배정도형으로 선언했다.

(1) 할당한 값

  • real_constant = 1.12345678987654321E0
  • double_constant = 1.12345678987654321D0

(2) 실제로 출력된 값

  • real_constant = 1.12345684
  • double_constant = 1.1234567898765433

E0, D0는 모두 10의 0승, 즉 1을 의미하므로 real_constant, double_constant 각각의 변수에 사실상 1.2345678987654321이라는 숫자를 할당한 것이나 다름없다. 결과를 출력해보니 실수형으로 선언한 real_constant는 소수점 아래 6번째 자리까지, 배정도형으로 선언한 double_constant는 소수점 아래 15번째 자리까지 정확하게 표현하고, 그 뒤에는 이상한 숫자들이 붙은 것을 확인할 수 있다.

이처럼 Fortran은 메모리 절약 및 속도 향상을 위해 내부적으로 긴 소수는 적당히 잘라서 계산하는데, 만일 더 많은 자리수를 정확하게 표현하고 싶다면 double precision을 사용하면 되나 그로 인한 메모리 증가와 속도 감소는 감수해야 한다.

위 캡처 화면에서 빨간색 박스를 쳐둔 부분이 코드 실행 결과이다. Fortran 프로그램을 작성하는 방법은 이 글에서 차근차근 다룰 예정이니 일단은 결과만 보고 넘어가자!

3) 정수형 연산 vs 실수형 연산

11 나누기 2를 하고 싶은 상황이라고 생각해보자. 11은 2로 나누어 떨어지지 않으므로 결과가 실수가 나올텐데, 만약 Fortran에게 '11/2'를 계산해달라고 하면 결과로 5.5가 아니라 5를 출력한다. 이는 정수형 연산과 실수형 연산의 차이 때문이다.

  • 정수형 연산: 식에 사용되는 숫자가 모두 정수인 경우, 결과도 무조건 정수로 출력한다.
  • ex) 11/2 에서 11, 2가 모두 정수이므로 결과도 5.5에서 소수점 아래를 무시하고 정수 5로 출력한다.
  • 실수형 연산: 식에 실수가 하나라도 포함되어 있다면, 결과도 실수로 출력한다.
  • ex) 11./2., 11./2, 11/2. 모두 분모, 분자가 모두 실수거나 적어도 하나는 실수이므로 결과도 실수로 출력한다(실수를 표현할 때 소수점 아래가 0이라면 생략하고 점만 찍어도 된다).

아래 캡처 화면을 보면 정확히 어떻게 출력되는지가 잘 보인다.

2. 변수(Variables)

상수(값)을 저장하는 기억 장소로, 상수와 마찬가지로 6가지 종류가 있다.

1) Fortran 변수 선언의 규칙

  1. 변수명은 영문자와 숫자의 조합이 가능하나, 첫자는 무조건 영문자여야 한다.
  2. 특수문자는 _(언더바)만 사용할 수 있으며, 공백은 불가능하다.
  3. 변수명은 프로그램명과 중복되어서는 안 된다.
  4. 각 변수는 한 번만 선언되어야 한다.

Q. 아래의 변수명 중에서 사용할 수 없는 것은?

  • A5
  • 5A : 첫자는 무조건 영문자여야 하는데 숫자로 시작했기 때문
  • VARIABLE
  • XY3Z4Q
  • AT&T: 특수문자는 _만 사용할 수 있는데 그외의 특수문자가 포함
  • NUMBER1
  • NO1
  • NO 1: 공백을 사용할 수 없는데 공백이 포함
  • NO_1

2) Fortran 변수 선언 방법

지난 글에서 일반적인 Fortran 프로그램의 구조는 아래와 같다고 설명했다.

Program 프로그램 이름
선언부(Declarations)
실행부(Statements)
stop
end program

여기서 '선언부'가 바로 프로그램에서 사용할 모든 변수를 선언하는 부분이다. Python에서는 코드를 짜면서 그때그때 변수를 선언해도 프로그램이 잘 알아먹지만, Fortran에서는 프로그램에서 사용할 모든 변수를 선언부에서 미리 선언해주어야 에러가 나지 않는다.

일반적인 선언문의 형태는 다음과 같다.

자료형:: 변수명

예시를 몇 가지 들어보겠다.

  • INTEGER:: var1, var2, var3
  • REAL:: x, y
  • CHARACTER(3):: A, B
  • LOGICAL:: N, M, P
  • COMPLEX:: B, C, D
  • DOUBLE PRECISION:: A, K, Z
  • var1, var2, var3라는 이름의 변수들은 '정수형'으로 선언
  • x, y라는 이름의 변수들은 '실수형'으로 선언
  • A, B라는 이름의 변수들은 '문자형'으로 선언. CHARACTER 뒤의 괄호 안에 있는 숫자는 '저장 가능한 문자 길이'를 의미한다. 예를 들어 후에 A = 'Fortran' 이렇게 7글자짜리 문자를 할당하더라도 이 경우 저장 가능한 문자의 길이가 3이므로 For까지만 출력된다.
  • N, M, P라는 이름의 변수들은 '논리형'으로 선언
  • B, C, D라는 이름의 변수들은 '복소수형'으로 선언
  • A, K, Z라는 이름의 변수들은 '배정도형'으로 선언

이런 식으로 변수 선언을 완료했다면, 그 뒤에 실행부에서 실제로 코드를 짤 때는 해당 자료형에 맞춰서 써야 한다. 예를 들어 앞서 var1을 integer, 즉 정수형으로 선언했는데, var1 = 3.14 이런 식으로 실수를 할당해버리면 에러가 날 수 있다.

3) 묵시적인 규칙(Implicit Rules)

Fortran에는 변수 선언에 대한 묵시적인 규칙(Implicit Rules)이 존재한다. 선언부에서 변수의 자료형을 선언하지 않았을 때, 변수 이름이 특정 영문자로 시작하면 '정수형', 그 외에는 '실수형'으로 자동으로 인식하는 기능이다.

  • 변수 이름이 I, J, K, L, M, N으로 시작: 정수형
  • 그 외: 실수형

Q. 선언부에서 변수의 자료형이 선언되지 않았을 때, 아래 변수들의 자료형은?

  • Morning(정수형: M으로 시작)
  • Korea(정수형: K로 시작)
  • Answer(실수형: 그 외의 영문자로 시작)
  • Seoul(실수형: 그 외의 영문자로 시작)

위의 I, J, K, L, M, N 규칙은 Fortran에 기본으로 내장된 규칙이고, 'Implicit문'을 이용하면 사용자가 Implicit rules를 변경할 수도 있다. Implicit문은 아래와 같은 형식으로 작성하면 된다.

IMPLICIT 자료형 (영문자 조건)

이는 괄호 안의 영문자로 시작하는 변수는 해당 자료형으로 자동으로 인식하겠다는 뜻이다. 예시를 몇 가지 들어 보겠다.

  • IMPLICIT INTEGER (A-Z)
  • IMPLICIT DOUBLE PRECISION (A-H, O-Z)
  • IMPLICIT REAL (A-C)
  • A부터 Z까지의 영문자로 시작하는 변수, 사실상 모든 변수를 '정수형'으로 자동 인식
  • A부터 H까지, O부터 Z까지의 영문자로 시작하는 변수를 '배정도형'으로 자동 인식
  • A부터 C까지의 영문자로 시작하는 변수를 '실수형'으로 자동 인식

'자동 인식'이라니까 뭔가 편해 보이지만, 실상은 그렇지 않다. 변수 선언을 깜빡한 채로 무심코 'Lemon'이라는 변수에 1.5라는 실수를 할당하면, Implicit rules에 의해 자동으로 정수형으로 인식되기 때문에 에러가 난다. 이를 방지하려면 매번 Implicit rules을 신경써서 코딩을 해야 하는데, 생각만 해도 여간 귀찮은 일이 아니다. 이런 귀찮음을 무릅쓰면서까지 Fortran을 배워야할까...?라는 의문이 들 때 혜성처럼 등장하는 명령어가 있었으니...

IMPLICIT NONE

 

이는 우리를 오히려 귀찮게 만드는 Implicit rules를 없애버리겠다는 뜻이다. Python과 같은 언어에 익숙한 사람이라면 모든 변수에 대한 자료형을 선언해줘야 한다는 점이 귀찮게 느껴질수도 있겠지만, 실상은 Implicit rules을 활용하는 게 훨씬 귀찮다... 앞으로 Fortran 코딩을 할 때는 무조건 "implicit none"을 쓰고, 모든 변수에 대한 자료형을 잘 선언해주도록 하자.

그러면 일반적인 Fortran 프로그램의 구조를 다음과 같이 다시 정리할 수 있다.

Program 프로그램 이름
implicit none
선언부(Declarations)
실행부(Statements)
stop
end program

4) Parameter문

Parameter문은 코드 전체를 통틀어 값이 변하지 않는 고유한 상수를 선언할 때 사용된다. pi나, 과학 분야의 수많은 상수들(볼츠만 상수, 아보가드로 수, 건조 공기에 대한 specific gas constant...)은 불변하는 값이 정해져 있으므로, 이럴 때 parameter문을 쓰면 좋다. parameter문은 선언부에서 변수 선언하면서 함께 적어주면 된다.

np.pi와 같이 pi값이 내장된 라이브러리를 지원하는 Python과 달리 Fortran에서는 pi를 하나의 변수로서 선언해주어야 하는데, Fortran에서 pi 값을 표현하는 데는 크게 두 가지 방법이 있다.

  • REAL, PARAMETER:: pi = 3.141592
  • REAL, PARAMETER:: pi = atan(1.) * 4.
  • pi는 무한소수이므로 소수점 아래 적당한 자리에서 끊어서 나타내는 방법
  • $tan($$\frac{pi}{4}$$)=1$임을 이용하면 $arctan(1)*4=pi$가 되는데, Fortran에서 arctan(아크탄젠트)는 atan으로 나타낸다.

5) 변수에 값 할당하기

한 기억장소(변수)에 값(상수)을 할당하기 위해 Fortran에서는 "=(등호)"을 사용한다.

  • ex) M = 8
  • M은 변수명, 8은 M이라는 변수에 할당된 상수
  • 여기서 등호는 양변이 같다는 뜻이 아니라 우변의 값을 좌변의 변수에 할당하겠다는 의미

6) 변수의 종류에 따른 기억장소 크기

(1) INTEGER(정수형)

  • 보통 4바이트(32비트) 크기(*1바이트=8비트)
  • 부호 1비트+이진법 숫자 31비트($2^{31}$=2,147,483,648, 최대 2,147,483,647, 최소 -2,147,483,647까지 취급 가능)
  • "INTEGER(바이트수)"와 같은 형식으로 기억장소 크기 지정 가능
  • ex1) INTEGER(1): 1바이트(8비트) 정수, $2^7$=128(-127~127) -> 3자리 이내 유효
  • ex2) INTEGER(2): 2바이트(16비트) 정수, $2^{15}$=32768(-32767~32767) -> 5자리 이내 유효

(2) REAL(실수형)

  • 보통 4바이트(32비트) 크기
  • 유효 자리수는 5~10자리 정도 기억
  • "REAL(바이트수)"와 같은 형식으로 기억장소 크기 지정 가능
  • ex) REAL(8): 8바이트(64비트) 실수 -> double precision(배정도형) 변수와 같아짐

(3) DOUBLE PRECISION(배정도형)

  • 8바이트(64비트) 크기
  • 유효 자리수는 REAL(실수형)의 약 2배(즉, 정밀도가 2배)
  • 하지만 실행 속도가 다소 느려지고 메모리를 2배나 먹는다는 단점이 있음

(4) CHARACTER(문자형)

  • "CHARACTER(문자의 개수)"와 같은 형식으로 기억장소 크기 지정 가능
  • ex) CHARACTER(3): 3글자까지 저장 가능
Comments