ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 내 맘대로 프로그램 설계 2. - 데이터 타입.
    프로그래밍/설계 2018. 1. 11. 10:08

    아무래도 너무 길어서 포스트를 2개(Section2, 3)로 나누어 다시 썼습니다.

    부족한 내용은 틈틈히 보강될 예정입니다.

    내 맘대로 하는 프로그램 설계 시리즈.

    Chapter1 - 간단한 데이터 처리(4섹션)

    2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.

    2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.(현재)

    2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.

    2018/05/29 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 4. - 고정 크기 데이터.

    2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.[부록]


    Chapter2 - 임의의 데이터 처리

    2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀.

    1. 시작하기.

    저번

    2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.

    글에서 프로그램은 데이터와 처리절차로 이루어져있다고 하였습니다.


    그렇다면 가장 기본적인 데이터의 종류는 무엇일까요?

    숫자? 문자? 그림?


    정답은 바로 숫자라고 할 수 있습니다.
    숫자가 있으면 문자, 그림을 모두 표현할 수 있기 때문이죠.
    흔히 컴퓨터가 0과 1만 처리할 수 있다고들 하는데, 문자와 그림을 처리할 수 있는 것을 생각하면 쉽게 이해할 수 있을 것입니다.


    그럼 숫자에서 가장 기본적인 처리절차는?

    당연히 이건 초등학생때 배우는 사칙연산이겠죠.


    이제 Dr.Racket을 켜고 사칙연산을 해봅시다.


    2. 간단한 데이터 처리.

    우리가 도구로 사용할 Racket이란 프로그램 언어의 기초적인 사용법을 알아봅시다.

    * 여기에서는 Racket의 모든 사용법을 다루지 않으며 htdp에 나오는 Racket의 사용법은 Racket 공식문서를 참고하시기 바랍니다.


    2.1 사칙연산.

    에디터창(정의창)에 아래의 코드를 따라치고 실행을 누르거나 대화창에 치고 엔터를 입력해보자.

    Code 2.1

    (+ 8 2)

    결과: 10

    '10'이라는 결과가 나온다.


    마찬가지로 빼기, 곱하기, 나누기를 하려면

    Code 2.2

    (- 8 2)
    (* 8 2)
    (/ 8 2)

    결과: 6, 16, 4

    을 차례로 치면 된다는 것을 유추할 수 있다.


    이제 Racket은

    (연산자 피연산자..피연산자)

    의 방식으로 계산을 한다는 것을 알았다.


    그런데 우리가 보통 사용하는

    (피연산자 연산자 피연산자..)

    방식보다 도대체 무엇이 더 나아서 이렇게 계산하는지 의문이 생길 수 있다.


    그렇다면, 1+2+3+4*5*6-7을 계산해보자.

    사칙연산의 순서를 고려해보면 $$1+2+3+ (4 \times 5 \times 6) - 7=119$$이고, Racket에서는 다음과 같이 표현할 수 있다.

    Code 2.3

    (- (+ 1 2 3 (* 4 5 6)) 7)

    결과: 119
    * 차근차근 결과를 확인해보고 싶다면 '한 단계씩 실행'을 누르면 된다.


    Racket의 계산 방법은 그냥 눈으로 읽기에는 약간 힘들 수는 있지만 어떠한 부분이 먼저 계산되어야 하는지(예: 덧셈과 곱셈의 연산우선순위)를 고려하지 않아도 되고, 연산자를 어디에서 찾아야 하는지(항상 괄호 시작 바로 뒤에 있다.) 알 수있는 장점이 있다.

    이러한 계산 방법은 한꺼번에 복잡한 명령을 처리해야 하는 프로그래밍에서 효율적이다.


    그리고 (+ 1 2 3)처럼 연산자 기호를 1개만 사용하더라도 여러개의 숫자를 계산할 수 있다.

    종이에 적어야 된다면 1 2와 12처럼 띄어쓰기에 주의하여 판독해야겠지만 컴퓨터를 사용하다보니 띄어쓰기의 모호함이란 단점은 상쇄된다.

    +. 전위, 중위, 후위 표기법.

    https://black7375.tumblr.com/post/169264990885/전위-중위-후위-표기법

    전위 표기법이 우리가 사용하는 Racket에서 쓰는 방식이고, 중위가 평소 수학을 할때 쓰던 방식이다.

    참고로 후위 표기법은 자료구조라는 과목에서 스택을 통해 배우게 될텐데, 그냥 알아두어도 좋다.

    컴파일러 같은 곳에서도 후위 표기법을 사용한다.


    * code 2.3에서의 (+ 1 2 3)처럼 그룹으로 계산하는 방식은 원래 전위 표기법에서 가능한 것이 아니라 Racket에서 편하게 계산하기 위해 추가된 문법이라 생각하면 된다.

    * Racet에서는 (+ (1) (2)) 같이 여분의 괄호는 허용되지 않습니다. 괄호의 바로 다음을 연산자로 보기 때문이라 생각하면 됩니다.


    2.2 확장된 숫자 계산.

    지금까지 사칙연산을 Racket을 사용해서 해보았습니다.

    이제 어떤 연산들을 기본적으로 지원하는지 알아봅시다.


    차례대로 루트, 제곱, 몫, 나머지(흔히 말하는 mod), 자연로그, sin(라디안 기준)입니다.

    $$\sqrt{a} \Rightarrow (sqrt \; a) \\
    a^b \Rightarrow (expt \; a \; b) \\
    a/b \Rightarrow (quotient\; a\; b) \\
    a \% b \Rightarrow (remainder\; a\; b) \\
    \ln a \Rightarrow (log \; a) \\
    \sin a \Rightarrow (sin \; a) $$

    * 다른 삼각함수인 cos, tan도 그대로 사용하면 됩니다.

    * 여기의 연산들은 그룹으로 하는 연산을 지원하지 않아 각각 허용하는 인자(argument, 지금까지 피연산자라고 불렀음.)의 갯수가 적거나 초과하면

    expects only 허용인자갯수 arguments, but found 사용자입력인자갯수

    같은 경고가 뜨며 답이 나오지 않습니다.


    그리고 (< 숫자 숫자), (>= 숫자 숫자)와 같은 연산 또한 할 수 있습니다.


    그럼,

    Code 2.4

    (sqrt 4)
    (sqrt 2)

    결과: 2, #i1.4142135623730951

    를 차례대로 실행해봅시다.


    첫번째는 2, 두번째는 #i1.4142135623730951가 나옵니다.

    여기서 Racket은 유리수가 아닌 실수일때 #i로 표시하고 근사값(Inexact Number)를 보여준다는 것을 알 수 있습니다.

    루트2라는 끝이 안나오는 무한한 숫자를 정확한 수로 표현하는 것은 불가능하기 때문에 어찌보면 당연한 일이기도 하죠.


    Racket에서 근사값 처리를 어떻게 하는지 간략하게나마 알아보기 위해 아래의 코드를 사용해봅시다.


    Code 2.5

    (- 1   0.9    )
    (- 1   #i0.9  )
    (- #i1 #i0.9  )
    (/ 1   3      )
    (* 10  (/ 1 3))

    결과: 0.1, #i0.09999999999999998, #i0.09999999999999998, 0.3, 3.3


    첫번째 값은 정확한 값이기 때문에 0.1이라는 결과가 나옵니다. 그러나 두번째의 #i0.9나 세번째의 #i1, #i0.9는 근사값을 가지고 있기 때문에 근사값으로 값을 처리하여 보여줍니다. 이렇게 근사값이 나오는 것은 원하지 않는 값이 나올 수 있으므로 프로그램을 작성할 때 조심해야 합니다.


    그러나 4번째의 0.3의 값은 의외죠?

    #i0.333333이라 나올줄 알았는데 0.3이라고만 표시됩니다.


    이는 Racket이 정확한 숫자와 부정확한 숫자를 구분하고,
    정확한 숫자일 경우 최대한 정밀도를 보정하기 때문입니다.

    내부적으로 3분의 1로 처리가 되었다는 뜻.


    그냥 0.3이 아니라는 증거는 마지막 3.3이란 결과를 통해 알 수 있습니다.


    이번에는 또 다른 연산자를 사용해봅시다.

    Code 2.6

    (>= 11 10)
    (<  10 10)

    결과: #true, #false


    부등호의 표시가 맞았는지, 틀렸는지에 대하여 판독하여 보여주죠?


    이제 참과 거짓값등 다른 데이터를 다루는 방법을 알아보도록 합시다.


    2.3 데이터.

    방금 전까지는 숫자를 다루었습니다.

    숫자는 데이터의 한 유형(이하 타입)입니다.

    숫자를 모아놓은 집합의 경우는 집합안의 각각의 원소가 더 작은 범위로 구분할 수 있기 때문에 복합 데이터(Compound Data)라 분류할 수 있습니다. 반면, 숫자 같은 경우는 쪼갤수 없기에 원자 데이터(Atomic Data)라 부릅니다.


    이제 다른 종류의 간단한 데이터를 Racket을 이용하여 다루어봅시다.


    그중 첫번째는 불린입니다.


    2.4 불린값(Boolean).

    불린(Boolean)은 고등학교 수학의 불대수 또는 정보시간에 조금이나마 배웠을 겁니다.(컴퓨터공학과라면 이산수학이나 논리회로때 또 보겠지만.)

    참(true) 또는 거짓(false)을 연산으로 하는 것입니다.

    부등호의 결과가 바로 불린 값이었던 것이죠!!


    불린은 논리연산이라는 것을 사용하여 값을 다룰 수 있습니다.

    기억이 안나거나 처음 배우는 것이라면 아래 링크를 한번 보고 옵시다.

    논리 연산 - 나무위키

    부울 대수(Boolean Algebra)는 19세기 중반 영국의 수학자 조지 부울(George Boole, 1815년 11월 2일 ~ 1864년 12월 8일)이 고안하고 형식화한 대수 체계를 의미한다. 논리 연산(logical operation, logical connective)으로도 불리운다. 수리 논리학이나 컴퓨터공학과에서, 두 개의 상태인 참(1, T, True)과 거짓(0, F, False)으로 부울 연산(Boolean expression)이라 한다.[1] 부울 대수의 출현 이후로 논리학은 기호논리학의 성향이 강해지기 시작한다.


    1을 참으로 0을 거짓으로 구분하는 언어도 있지만, Racket은 #true를 참으로 #false를 거짓으로 취급합니다.

    true와 false도 되는 것 같기는 하지만 #true와 #false가 Racket에서 표준이니 #을 앞에 붙이는 방식을 따르는 것이 좋습니다.


    논리연산을 Racket으로 하는 몇가지 방법을 배워봅시다.

    $$a\land b \Rightarrow (and\; a\; b) \\ a \lor b \Rightarrow (or\; a\; b) \\ \bar{a} \Rightarrow (not\; a)$$


    지금까지 배운 것들을 활용하여 아래의 문제를 Racet을 이용하여 풀어봅시다.


    문제 2.1

    2의 3제곱이 12초과이고, ln5가 1이상인가?


    문제를 코드로 풀어보면 다음과 같다.

    코드:

    Code 2.7

    (and (> 12 (expt 2 3))
         (<= 1 (log  5  )))

    결과: #true


    또는(OR), 그리고(AND)와 같은 것을 사용하는 것은 수학을 배웠을 때 충분히 경험했을 겁니다.

    계속되는 수학시간 같은 느낌에 슬슬 지겨워질 때도 되었는데, 간단히나마 다른 자료형을 다루어봅시다.


    2.5 기호(Symbol).

    기호는 작은따옴표 뒤에 이어지는 문자순열(Characters Sequence)입니다.

    * 스페이스나 쉼표는 사용할 수 없다.


    기호 테스트를 위해

    Code 2.8

    'racket~*5

    를 치면 'racket~*5가 반환되는 것을 확인할 수 있습니다.


    Racket은 기호에 대한 기본 연산으로 symbol=? 라는 비교연산을 제공합니다.

    이를 비교해서 불린값으로 반환하고요.

    Code 2.9

    (symbol=? 'racket~*5 'racket~*5)
    (symbol=? 'racket~*5 'abc123   )

    결과: #true, #false


    2.6 문자열(String).

    문자열은 큰따옴표로 묶인 문자집합(Text)입니다.


    문자열 테스트를 위해 대화창에

    Code 2.10

    "Hello, World"

    결과: "Hello, World"

    라고 쳐봅시다.


    "Hello, World"라고 반환이 되었을 겁니다.


    그렇다면 이제까지 해왔던 것처럼, 간단한 문자열 연산을 해봅시다.

    • string-append: 문자열을 연결.
    • string-length: 문자열의 길이 계산.
    • string->number: 문자열을 숫자로 변환.
    • number->string: 숫자를 문자열로 변환.
    • string-ith: (string-ith 문자열 숫자)로 사용하며, 숫자 번째에 있는 문자열 1개를 추출합니다.(0부터 시작)


    간단하게 문제를 풀고 넘어갑시다.

    문제 2.2

    단어 Hello와 World가 있다고 할 때 이를 붙여 Code 2.10에서 나왔던 "Hello, World"를 만들고 문자열 길이를 구해보세요.


    코드:

    Code 2.11

    (string-length (string-append "Hello" ", " "World"))

    결과: 12


    2.7 이미지(Image).

    D맨[from D Lang.org]

    전 D언어의 마스코트인 D맨을 사용해보겠습니다.

    이유는 그냥 은근히 귀여워서?

    (사실 생각나는게 딱히 없어서 ㅜㅜ)


    이미지도 연산자가 존재하겠죠?

    'image-width'는 이미지의 가로, 'image-height'는 이미지의 세로크기를 구해줍니다.


    그래서

    Code 2.12 - 1

    (image-width )

    결과: 463


    사용해보았더니 아래의 사진처럼 에러가 뜨게 됩니다.


    에러가 난 내용을 해석해보면 image-width라는 함수가 정의되지 않았다고 뜹니다.


    이를 해결하는 방법은 '언어-배움꾸러미추가'에 들어가서 '2htdp\image.rkt'라는 것을 추가하는 것 입니다.

    그 후 실행버튼을 한번 눌러준 후부터는 쓸 수 있습니다.


    갑자기 함수니, 배움꾸러미니 혼란스럽죠?


    함수는 특정한 동작을 수행하는 일정 코드의 부분입니다.

    처음에 언급했던 '데이터-처리절차'중 넓게보면 '처리절차'에 해당된다고 생각하면 되는 것이죠.

    지금까지 저희가 단순히 '연산자'라고 불러왔던 '+', '-'부터 'number->string'과 같은 것들도 특정한 동작을 수행하도록 정의된 것이므로 사실 함수였습니다.

    (함수이름 인자값 인자값)

    구조로 사용하고 있었다는 것.


    프로그래밍을 하는 행위가 '컴퓨터 명령어'를 작성한다고도 부르는데,

    (동사 명사)

    영어의 '명령문' 어순과 유사하게 일반적으로 '동사 명사' 구조를 가집니다.


    배움꾸러미는 이미 정의가 되어있는 함수들을 비슷한 기능에 따라 모아놓은 라이브러리입니다.

    마치 도서관(라이브러리)에 책들(함수)을 모아놓은 것처럼요.


    예를 들면 +-*/는 '사칙연산'이라는 라이브러리(배움 꾸러미)로 묶을 수 있고, 우리가 추가한 2htdp/image.rkt라는 라이브러리는 이미지와 관련된 함수들을 모아서 만들어놓은 것이겠죠.

    * HtDP는 쉽게 접근을 하기 위해 배움꾸러미라고 하지만, 일반적으로 라이브러리라고 표현합니다.


    마우스로 '배움꾸러미 추가'를 눌러 라이브러리를 추가하는 것이 아니라, 코드로도 추가할 수 있습니다.

    (require 라이브러리이름)

    의 형태로 말이죠.


    저는 앞으로 require을 사용하여 라이브러리를 사용할 것입니다.

    그럼 배움 꾸러미는 제거하고, require 함수를 사용하여 2htdp/image 라이브러리를 불러와 봅시다.

    Code 2.12 - 2

    (require 2htdp/image)

    물론 image-width의 앞에 써놓아야 합니다.

    먼저 2htdp/image의 내용을 읽어야, image-width가 무엇인지 알 수 있을테니까요.


    2.8 널 값(Null)

    Null은 값이 없다는 것을 나타낸다.


    흔히 값이 없다고 하면 0이라고 생각하지만,

    0도 '숫자'라는 데이터의 한 종류이기 때문에 값이 없다는 것을 나타내는 Null이 필요합니다.


    Code 2.13

    null

    결과: '()


    지금까지 다른 데이터와 다르게 '()라는 결과가 나왔습니다.

    그 이유는 Section 5에서 자세히 다루도록 하겠습니다.


    지금은 값이 없다란 뜻만 기억해두고 있으면 됩니다.

    2.9 데이터 판독과 타입.

    2.9.1 데이터 판독.

    지금까지 다양한 종류의 데이터를 알아보았습니다.

    Racket은 데이터의 타입들을 인식할 수 있는 함수들을 제공하여 사용자가 데이터의 종류를 구분할 필요가 생겼을 때 도와줍니다.


    예를 들어

    number?, boolean?, symbol?, string?, null? 은

    각각 숫자, 논리, 심볼, 문자열, Null을 판독하여 #true와 #false로 반환해주는 함수입니다.


    equal?는 입력한 값이 같은지 체크해주는 함수입니다.

    역시 #true와 #false를 반환해주고요.


    이 외에도 integer?, real?같은 함수는 숫자 중에서도 정수와 실수 같이 제한된 데이터 타입을 판독하게 해줍니다.

    여기서 알 수 있는 것은 데이터의 범위나 한계에 따라서도 '데이터 타입'은 달라질 수 있다는 것입니다.


    2.9.2 타입.

    Section2 마지막으로는 데이터 타입에 대하여 조금 더 논하겠습니다.


    저희는 지금까지 정수, 실수, 심볼, 문자열등의 데이터 타입들을 다루었습니다.

    데이터 타입이 중요한 이유는 데이터 타입에 따라 연산과 의미, 저장방식들이 달라지기 때문입니다.


    - 의미

    예를 들어 숫자 1과 문자열 "1"이 같은 의미로 받아들일 수 있을까요?


    아닙니다.

    문자열 "1"은 그저 아라비아 숫자 '1'이란 문자일 뿐이지만, 숫자 1은 표시해놓은 '1'은 아라비아 숫자의 모습을 가지고 있지만, 한글 '일', 한자 '一'(한 일) 등과도 같은 의미를 가지고 있습니다.


    - 연산

    두 번째로 살펴볼 것은 연산입니다.

    데이터 타입에 따라 사용할 수 있는 연산이 다릅니다.


    여기서도 예를 들어

    '+' 연산을 문자열에서도 사용할 수 있나 생각해봅시다.


    사용할 수 없죠.

    물론 어떤 언어에서는 +를 string-append처럼 문자열끼리 연결 용도로도 사용하게 해주지만

    숫자에서의 +와는 엄연히 다른 연산입니다.


    만약 숫자에서도 문자열의 +와 같은 의미라면 1+2는 12가 되었어야 합니다.

    동일한 처리절자가 이루어지지 않는다면 같은 연산이 아니고, 겉으로 표현되는 형태만 같은 것 뿐입니다.


    - 저장방식

    역시 데이터 타입에 따라 저장 방식도 달라지게 됩니다.

    앞에서 데이터 타입은 데이터의 범위와 한계에 따라서도 다르다는 말과 일맥상통합니다.


    이미지를 일반적인 텍스트 뷰어로 열 수 없고, 텍스트도 일반적인 이미지 뷰어로 열 수 없는 것처럼 데이터마다 범위, 한계, 저장방식이 달라지게 됩니다.


    +.

    https://black7375.tumblr.com/post/170301722165/정적-타이핑-vs-동적-타이핑

    https://black7375.tumblr.com/post/170301722165/%EC%A0%95%EC%A0%81-%ED%83%80%EC%9D%B4%ED%95%91-vs-%EB%8F%99%EC%A0%81-%ED%83%80%EC%9D%B4%ED%95%91


    3. 섹션2 후기.

    어때요?

    할 만 했나요?


    매우 간단한 프로그램들을 만들어보았습니다.

    다음엔 함수라는 것을 본격적으로 배워봅시다.

    +.

    이 글의 Code라 표시된 것들은 제 깃허브에서 그대로 확인하실 수 있습니다.

    https://github.com/black7375/Design-your-own-program.

    black7375/Design-your-own-program.

    Contribute to Design-your-own-program. development by creating an account on GitHub.


    다운받아 DR.Racket으로 열어보면 정상적으로 사용할 수 있습니다.


    끝~~~


    댓글

Designed by black7375.