ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자료구조 - 2 | 자료의 표현
    컴퓨터 공학/자료구조 2022. 9. 11. 01:32

    디지털 시스템에서의 자료 표현

    컴퓨터에서는 숫자, 문자, 그림, 소리 등의 모든 형식의 자료를 내부적으로 2진수 코드로 변환하여 저장하고 처리한다. 여기서 말하는 2진수 코드란 0과 1의 조합으로 이루어진 코드를 의미하며, 이때 0 또는 1을 나타내는 기본적인 단위를 비트라고 한다.

     

    즉, 디지털 시스템에서는 어떠한 형태의 자료든지 0 또는 1로 이루어진 비트단위로 정보를 처리하게 된다.

    따라서 만약 n개의 비트가 존재한다면, 이를 이용해 2^n개의 상태를 표현할 수 있다.

    컴퓨터 내부에서 표현할 수 있는 자료

    컴퓨터 내부에서 자료를 표현하는 방법

    컴퓨터 내부에서 이러한 2진수 방식을 이용해 표현할 수 있는 자료의 형태는 다음과 같다.

    • 수치 자료
    • 문자 자료
    • 논리 자료
    • 포인터 자료
    • 문자열 자료

    이에 관한 자세한 내용은 아래에서 순차적으로 확인할 수 있도록 하였다.


    수치 자료의 표현 - 10진수 방식

    초기에는 수치 자료의 표현을 위해 인간에게 친숙한 10진수 방식을 사용하였다. 이는 이후 자릿수 계산의 어려움 등으로 인해 2진수 방식으로 변환되었다.

    존(Zone) 형식의 표현

    10진수 한 자리를 표현하기 위해 1byte(8bit)를 사용하는 방식으로, 존 영역과 수치 영역으로 나뉜다.

    존 형식의 구조

    이때 존 영역은 자릿수 또는 부호를 나타내기 위한 정보를 담는 데 사용하고, 수치 영역은 해당 자릿수에 해당하는 실제 수치를 2진수로 표시하는 데 사용하였다. 따라서 여러 자리의 10진수를 표현하기 위해, 각 자릿수만큼 존 형식을 연결하여 사용하였고, 마지막 자리의 존 영역에는 부호를 표현하였다. 이때 양수는 1100으로, 음수는 1101로 표현한다.

    +213을 존 형식으로 나타낸 예시
    -213을 존 형식으로 나타낸 예시

    팩(Pack) 형식의 표현

    10진수 한 자리를 표현하기 위해 4bit를 사용하는 방식으로, 존 형식에서 존 영역을 제외한 형태이다.

    자릿수를 따로 표현하지 않고, 제일 마지막 4bit에 부호를 표시하였다. 이때 양수는 1100으로, 음수는 1101로 표현한다.

    +213과 -213을 팩 형식으로 나타낸 예시


    수치 자료의 표현 - 2진수 방식 (정수)

    수치 자료를 표현하기 위해 10진수를 사용하던 방식은 비록 인간이 그 체계를 이해하기에는 편리했을지 몰라도, 기계인 컴퓨터가 해당 자료를 이용해 연산을 진행하기에는 불편함이 있었다. 따라서 아예 수치 자료를 표현함에 있어서 2진수 방식을 택하기 시작했다.

    n비트 부호 절댓값 형식

    수치 자료를 n개의 비트를 이용해 절댓값으로 나타내는 방식이다. 예를 들어 8비트 시스템이라고 한다면 8개의 비트를, 16비트 시스템이라고 한다면 16개의 비트를 이용해 수치 자료 하나를 표현하는 방식이다.

     

    이때 가장 최상위 1bit는 부호를 표시하는 데 사용하고, 나머지 비트들은 절댓값으로 그 수치를 표현한다. 물론 해당 수치 표현에는 2진수의 방식을 사용한다.

    +21과 -21의 부호와 절댓값 표현 예시

    1의 보수 형식

    음수를 표현할 때 최상위 비트의 부호 비트를 사용하는 대신 1의 보수를 사용하는 방식이다.

    이때 1의 보수라 함은 n개의 비트가 모두 1인 이진수에서 변환하려는 이진수를 뺀 값을 의미한다. 어렵게 느껴질 수 있지만, 실제로는 0은 1로, 1은 0으로 값을 바꿔주기만 하면 끝이다.

    1의 보수 형식 표현 과정

    이때 실제 표현할 절댓값은 n-1bit에 해당하는 범위만 사용할 수 있다. 최상위 비트까지 절댓값을 표현하는 데 사용한다면, 양수인지 음수인지 판별이 불가능하기 때문이다. (최상위 비트를 부호 비트로 사용한 것은 아니지만, 보수 형식에서도 여전히 최상위 비트가 0이면 양수, 1이면 음수이다.)

     

    가장 최상위 비트에 부호를 표현하는 방식이 인간이 이해하기에는 훨씬 직관적이고 좋지만, 그럼에도 이러한 음수를 보수로 변환하여 표현하는 이유는 컴퓨터가 계산을 함에 있어서 어려움이 있기 때문이다.

    부호 비트를 사용하는 경우, 어떤 부호 비트끼리 만나 계산하는지에 따른 경우의 수를 고려하여, 그에 맞는 가산기 또는 감산기 회로를 구성해야 한다. 따라서 컴퓨터가 수를 계산하는 데에 있어 훨씬 복잡하다는 것이다.

     

    반면 이렇게 보수의 형식을 사용하게 되면, 컴퓨터가 그냥 가산기만 이용해 수를 더해주면 끝이다. 음수가 오든 양수가 오든 상관없이 일괄적으로 가산기만을 이용해 덧셈만으로 결과값을 얻을 수 있다는 것이다.

     

    하지만 1의 보수 형식이 문제가 없는 것은 아니다. 바로 0의 표현이 2개가 생길 수 있다는 것이다.

    아래의 표는 8bit를 기준으로 하여 간단한 수들을 1의 보수 형식으로 나타낸 것이다.

    양수 음수
    DEC BIN DEC BIN
    0 0000 0000 -0 1111 1111
    1 0000 0001 -1 1111 1110
    2 0000 0010 -2 1111 1101
    3 0000 0011 -3 1111 1100
    ··· ··· ··· ···
    127 0111 1111 -127 1000 0000

    위의 표를 보면 0과 -0이 존재함을 알 수 있다. 분명 0은 0000 0000으로 표현될 것인데 왜 -0이 또 존재하는 것일까?

    위의 표에서 서로 절댓값이 같은 두 양수와 음수를 서로 더한다고 생각해보자. 10진수로 따지면 모두 0의 결과가 나오는 값이지만, 2진수로 따지면 항상 1111 1111의 값이 나온다.

     

    따라서 0을 표현함에 있어서 0000 0000의 방식과 1111 1111의 방식 두 개가 존재하게 된다. 그리고 이는 컴퓨터가 0을 처리함에 있어 추가적인 작업을 진행해야 하는 결과로 이어진다.

    2의 보수 형식

    이러한 문제를 해결하기 위한 가장 쉬운 방법은 음수 영역을 표현할 때 +1을 추가적으로 더해주는 것이다.

    양수 음수
    DEC BIN DEC BIN
    0 0000 0000 -1 1111 1111
    1 0000 0001 -2 1111 1110
    2 0000 0010 -3 1111 1101
    3 0000 0011 -4 1111 1100
    ··· ··· ··· ···
    127 0111 1111 -128 1000 0000

    그러면 1의 보수 형식에서 만들어지는 표에서 양수는 같지만, 음수는 +1이 하나씩 더해진 형태가 보이게 된다.

    이때 -0의 경우 의도한 대로 사라진 것을 확인할 수 있다. 또한 여기서는 설명하지 않았지만, 이러한 2의 보수 형식은 오버플로우가 일어난 경우에도 별다른 조치 없이 값을 간단하게 계산할 수 있다.

     

    따라서 현대의 컴퓨터 시스템에서는 모두 2의 보수 형식을 이용하여 음수를 표현하고 있다.

    2의 보수 형식 표현 과정

    이를 위해서는 위와 같이 먼저 1의 보수를 구해주고, 이후에 1을 추가적으로 더해주기만 하면 된다. 이때 만약 자리올림이 발생한다면, 이는 모두 계산해주어야 한다.

     

    아래의 링크는 2진수의 표현법에 대한 굉장히 자세하게 쓰인 글이다. 아래의 글을 참고하여 해당 포스트를 작성하지는 않았지만, 그 내용의 깊이가 훨씬 더 깊어서 꼭 한번 아래의 글을 정독했으면 한다.

     

    2진수의 수와 음수 표현법 [1의 보수와 2의 보수]

    안녕하세요. 오늘은 프로그래밍이 아닌 컴퓨터의 연산에 대해 이해해보고자 합니다. 우리가 흔히 프로그래밍을 할 때는 그나마 사람에 가까운 언어로 된 고급언어들로 작성을 하지만 실제 컴퓨

    st-lab.tistory.com


    수치 자료의 표현 - 2진수 방식 (실수)

    지금까지 2진수를 이용하여 정수형 수치자료를 표현하는 방법에 대해 알아보았다. 음수를 2의 보수로 나타낸다는 것을 제외하면 그렇게 어려운 내용은 아니었다.

     

    반면 정수가 아닌 실수형(소수점) 수치 자료의 경우 조금은 어렵게 느껴질 수 있다.

    실수를 2진수로 표현하는 방법으로는 크게 고정소수점 방식과 부동소수점 방식이 있다. 하지만 이를 알아보기 전에 먼저 소수부에 위치한 수를 2진수로 어떻게 나타내는지부터 알아보도록 한다.

    소수부 표현 - 2진수

    정수부를 2진수로 변환할 때에는 10진수로 표현된 정수부를 2로 나누면서 몫이 1이 나올 때까지 반복한다. 이후 나누는 과정에서 만들어진 나머지 값들을 반대로 읽어나가면서 이진수로 변환할 수 있다.

     

    반대로 소수부를 2진수로 변환할 때에는 10진수로 표현된 소수부를 2로 곱하면서 정수부의 1 또는 0 값을 순서대로 읽어주는 것을 소수부가 0이 나올 때까지 반복하면 된다. 예를 들어 0.6875를 2진수로 변환한다고 생각해보자.

     

    0.6875 * 2 = 1.375 (1)

    0.375 * 2 = 0.75 (0)

    0.75 * 2 = 1.5 (1)

    0.5 * 2 = 1 (1)

     

    이러한 과정으로 진행될 것이고, 그 결과는 0.1011이다. 즉, 10진수 0.6875를 2진수로 변환하면 0.1011이 된다는 것이다.

    물론 위와 같은 예시는 깔끔한 수가 나오도록 특정한 수를 예시로 든 것이다. 보통의 10진수 소수부를 2진수로 표현하게 된다면, 무한히 길게 표현되는 경우도 있다. 그런 경우에는 해당 시스템에서 수치자료를 표현하는 데 사용하는 비트수에 맞게 끊어주어야 한다. 즉, 실수 영역에서는 10진수를 2진수로 표현하는 것 자체가 수를 부정확하게 만드는 일이다.

    고정소수점 방식

    고정소수점 방식은 소수점이 고정되어 있는 형태로 실수를 표현하는 방식이다. 가장 최상위 비트는 부호 비트로 지정하여 양수와 음수를 나타낸다. (0이 양수, 1이 음수)

     

    이후 나머지 비트들을 정수부와 소수부로 적절히 분배하여 표현을 한다. 만약 32bit 고정소수점 방식으로 실수를 나타낸다고 해보자. 그렇다면 첫 칸을 부호 비트로, 다음 15칸을 정수부로, 다음 16칸을 소수부로 사용하게 된다.

     

    따라서 17.6875를 32bit 고정소수점 방식으로 나타낸다고 하면 아래와 같다.

    0 000000000100111 1011000000000000 (색별로 각각 부호 비트, 정수부, 소수부)

    정수부와 소수부는 각자 10진수를 2진수로 변환하는 방식으로 변환한 다음, 남은 부분은 0으로 채워 넣은 것이다.

     

    이러한 고정소수점 방식은 소수부를 2진수로 변환할 수만 있다면, 크게 어렵지 않으면서 직관적인 방법이다.

    단, 비트수에 비해 버려지는 부분이 많아 표현 가능한 수의 범위가 낮고, 그에 따라 자연스럽게 정밀도 또한 낮아지기 때문에 보통의 시스템에서는 고정소수점 방식이 아닌 부동소수점 방식을 자주 사용한다.

    부동소수점 방식

    부동소수점 방식은 소수점이 고정되어 있지 않은 형태로 실수를 표현한다. 여기서 말하는 부동이 움직이지 않는다는 뜻처럼 들려 번역이 아주 잘못된 단어라 생각이 드는데, 실제 부동소수점은 Floating Point로 떠있는 소수점이라는 의미이다. Fixed 되어 있지 않기 때문에 소수점을 유동적으로 움직일 수 있다는 뜻이다. (물에 떠있다는 뜻의 부유(浮遊)와 같은 한자어를 쓰기 때문에, 부동이라는 말로 번역된 듯하다.)

     

    이때 소수점을 유동적으로 옮긴다는 뜻은 2진수 실수의 정수부를 무조건 1로 만들어준다는 뜻이다

    예를 들어 17.6875(10진수)를 2진수로 변환하면 100111.1011인데, 이를 1.001111011 × 2^5와 같은 형태로 변환한다는 것이다. 이를 정규화라고 부른다.

     

    이렇게 정수부가 무조건 1이 되도록 소수점을 옮기고 나면, 해당 실수를 지수부(Exponent)와 가수부(Mantissa)로 표현할 수 있다. 위의 1.001111011 × 2^5 예시에서 5가 지수부이고, 소수점 아래의 001111011이 가수부이다.

    가장 최상위 비트를 부호 비트로 사용하는 것은 고정소수점 방식과 동일하다.

     

    32bit를 사용하는 부동소수점 방식 (Float)
    64bit를 사용하는 부동소수점 방식 (Double)

    단, 여기서 지수부는 그대로 저장하지는 않고, bias라는 특정 값을 추가로 더해준 다음 이를 지수부에 사용한다. 이때 bias의 값은 32bit에서는 127, 64bit에서는 1023을 사용한다. 그렇다면 이러한 bias값을 추가로 더해주는 이유는 무엇일까?

     

    바로 지수부가 음수로 표현될 수도 있기 때문이다. 예를 들어 0.00101이라는 2진수 실수가 있다고 한다. 이러한 실수를 정규화해 주면, 1.01 × 2^(-3)으로 나타낼 수 있다. 즉, 지수부가 -3이라는 음수를 가지게 된다. 따라서 이러한 경우 해당 음수를 표현하기 위한 방법을 따로 만들어야 하는데, 지수부만을 위한 부호 비트를 할당하기도 복잡하다

     

    이러한 이유로 32bit를 기준으로 지수부는 8bit(256)의 절반인 127을 bias로 하여 의무적으로 지수부에 더하게 하였다. 따라서 0에서 127구간은 음수, 128에서 255구간은 양수로 이해하기로 정한 것이다.

    마찬가지로 64bit에서는 지수부를 11bit 사용하는데, 이에 절반인 1023을 bias로 사용하는 것이다.

     

    따라서 해당 내용을 모두 종합하여 10진수 실수인 17.6875를 32bit 부동소수점 방식으로 나타내면 다음과 같다.

    1. 10진수 실수를 2진수 실수로 변환: 17.6875 (DEC) → 100111.1011 (BIN)
    2. 정규화: 1.001111011 × 2^5
    3. bias계산: 5 + 127 = 132 (DEC) → 1000 0100 (BIN)
    4. 부동소수점 표현: 0 10000100 00111101100000000000000 (색별로 각각 부호 비트, 지수부, 가수부)

    문자 자료의 표현

    컴퓨터에서는 문자를 표현하기 위해서도 역시 내부적으로 2진수를 사용한다. 이때 미리 만들어진 표를 이용해, 특정 이진수 조합과 맞는 문자를 인간이 쉽게 알아볼 수 있는 이미지의 형태로 나타내 주는 것이다. 따라서 컴퓨터에서 문자 자료를 표현하기 위해서는 각 문자에 맞는 2진수 코드표가 존재해야만 한다. 그리고 이러한 코드표는 다음과 같이 여러 종류가 있다.

    BCD 코드

    BCD 코드 방식은 6bit를 사용하여 문자 하나를 표현한다. 이때 상위 2bit는 존 비트이고, 하위 4bit는 2진수 비트이다. 이렇게 만들어진 존 비트와 2진수 비트를 조합하여, 아라비아 숫자 0에서 9까지와 영어 대문자를 표현할 수 있다.

    BCD 코드의 구성

    예를 들어 010010은 문자 B를 나타내는 식이다. 이는 특별한 계산과정이 필요 없이 그냥 인터넷에 떠도는 BCD 코드표 하나만 있으면 언제든지 쉽게 6자리 이진수에 대응하는 문자를 찾아낼 수 있다.

    EBCDIC 코드

    EBCDIC 코드는 BCD 코드의 확장판으로, 8bit를 사용하여 문자 하나를 표현한다. 이때 상위 4bit는 존 비트이고, 하위 4bit는 2진수 비트이다. BCD 코드와 마찬가지로 존 비트와 2진수 비트를 조합하여 문자를 표현한다.

     

    이때 아라비아 숫자 0에서 9까지와 영어 대문자 및 소문자, 간단한 특수문자까지 표현할 수 있다.

    EBCDIC 코드의 구성

    ASCII 코드

    코딩을 자주 하는 사람이라면 가장 친숙하게 다가올 코드인 ASCII 코드이다. 아스키코드는 7bit를 사용하여 하나의 문자를 표현하는데, 상위 3bit는 존 비트이고, 하위 4bit는 2진수 비트이다. 마찬가지로 이들을 적절히 조합하여 0에서 9까지의 아라비아 숫자와 영어 대소문자, 특수문자를 표현할 수 있다.

    ASCII 코드의 구성

    아스키코드 역시 코드표가 인터넷에 널려있으므로, 해당 코드표를 보고 대응하는 문자를 쉽게 찾을 수 있다. 이때 보통의 아스키코드표에서는 존 비트와 숫자 비트를 합친 2진수의 값을 10진수로 변환하여 간단하게 보여주는 형태가 많다. 따라서 A의 경우 아스키코드표에 65라 적혀있지만, 내부적으로는 100 0001로 존 비트 100과 숫자 비트 0001로 이루어진 형태이다. (10진수 65를 2진수로 변환하면 100 0001이다.)

    유니코드

    BCD, EBCDIC, ASCII 코드는 모두 아라비아 숫자, 영어 알파벳, 약간의 특수문자만을 표현할 수 있다. 하지만 세계에는 여러 나라의 언어들이 각자 존재하고, 새로운 특수문자는 얼마든지 많다. 따라서 이러한 문자들을 표현할 수 있어야 하는데, 해당 문제를 해결하기 위해 만든 국제 표준 코드가 바로 유니코드이다. (ISO/IEC 10646)

     

    유니코드는 2byte를 조합하여 하나의 글자를 표현하기 때문에, 1byte 코드로는 표현할 수 없었던 다양한 언어들을 표현할 수 있다.


    논리자료의 표현

    논리값은 참(true) 또는 거짓(false)으로 1 또는 0으로 간단하게 표현할 수 있다.

    이때 논리값을 표현하기 위해 1byte(8bit)를 사용한다고 하면, 다음과 같은 방법이 있다.

    방법 1

    • 참(true): 최하위 비트를 1로 표시 (0000 0001)
    • 거짓(false): 전체 비트를  0으로 표시 (0000 0000)

    방법 2

    • 참(true): 전체 비트를 1로 표시 (1111 1111)
    • 거짓(false): 전체 비트를 0으로 표시 (0000 0000)

    방법 3

    • 참(true): 하나 이상의 비트를 1로 표시 (0100 1001 등)
    • 거짓(false): 전체 비트를 0으로 표시 (0000 0000)

    포인터 자료의 표현

    포인터란 메모리의 주소를 표현하기 위해 사용하는 자료의 형식이다. C언어에서는 포인터 기능을 직접적으로 제공하는데, 이때 포인터 변수에 저장된 주소가 해당 자료 형식으로 저장된다.


    문자열 자료의 표현

    여러 문자로 이루어진 문자의 그룹을 하나의 자료로 취급하여 메모리에 연속적으로 저장하는 자료 형식이다.

    하나의 문자열 자료에 포함된 각각의 부분 문자열을 구분하는 방법은 다음과 같다.

    방법 1

    부분 문자열 사이에 특정 구분자를 사용하여 저장한다.

    세미콜론을 구분자로 사용하여 부분 문자열을 구분

    이러한 방식을 이용하면 메모리 이용률 측면에서는 효율적일 수 있다. 하지만 부분 문자열을 탐색하기 위해서는 전체적으로 탐색을 진행하면서 구분자를 식별해야 하기 때문에, 비효율적이다.

    방법 2

    가장 긴 문자열의 길이에 맞춰 고정 길이로 저장한다.

    가장 긴 문자열의 고정길이에 맞춰 부분 문자열을 구분

    이러한 방식을 이용하면 부분 문자열을 탐색하기에는 효율적일 수 있다. 하지만 낭비되는 메모리가 많기 때문에 메모리 이용률 측면에서는 비효율적이다.

    방법 3

    부분 문자열을 연속하여 저장하고, 각 부분 문자열에 대한 포인터를 사용한다.

    각 부분 문자열이 시작하는 지점의 주소를 포인터를 이용해 구분

    해당 방식은 메모리 이용률과 부분 문자열 탐색에 있어서 모두 효율적인 방식이라고 볼 수 있다. 낭비되는 메모리도 없을뿐더러, 포인터를 이용해 각 부분 문자열이 시작하는 주소로 빠르게 이동할 수 있기 때문이다.

    댓글