정보의 인코딩

ZoLAist's WikiNote
Zolaist (토론 | 기여) 사용자의 2018년 2월 2일 (금) 15:01 판 (새 문서: 21세기와 컴퓨터 2012년 2학기 [강의노트] 2.2 정보의 인코딩 : 한글은 어떻게 저장될까? (현재 편집 중) ==주요 개념== * 보수 : 임의의 진법...)

(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)
이동: 둘러보기, 검색

21세기와 컴퓨터 2012년 2학기

[강의노트] 2.2 정보의 인코딩 : 한글은 어떻게 저장될까?

(현재 편집 중)

주요 개념

  • 보수 : 임의의 진법으로 표현된 수를 10..000으로 뺀 수.
  • 1의 보수 : 2진수의 모든 숫자를 1은 0으로 0은 1로 바꾼 수.
  • 2의 보수 : 2진법의 수를 100..000으로 뺀 수. 1의 보수에 1을 더하여 쉽게 구할 수 있다.
  • ANSI : American National Standards Institute. 미표준국을 말하는데, 코드표를 이야기할 경우엔 ANSI에서 제정한 ASCII와 동일하다고 보면 된다. 지역별로 이를 조금씩 확장하여 사용하고 있다.
  • EUC-KR : ANSI의 한국형 확장판. 영문을 포함한 ANSI 코드 부분은 1바이트, 한글 등의 문자는 2바이트로 표현. 일부 중국식 한자나 아랍어 등은 표현하지 못한다.
  • EUC-JP : ANSI의 일본형 확장판. 영문을 포함한 ANSI 코드 부분은 1바이트, 일본어 등의 문자는 2바이트로 표현. 한글이나 아랍어 등은 표현하지 못한다.
  • 유니코드 : unicode. 세계에 존재하는 모든 문자를 표현하기 위해 제정된 표준 코드 표. 하나의 문자는 유일하게 하나의 수와 짝지어진다. 예를 들어 ‘A’는 65, ‘가’는 44032와, 아랍어 ‘م’는 17670에 대응된다. 유니코드 형식에 따르면, 희귀한 일부 문자들을 제외한 대부분의 문자는 하나 글자당 2바이트로 표현될 수 있다.
  • 리틀 엔디안 : Little Endian.
  • 빅 엔디안 : Big Endian.
  • BOM : Byte Order Mark.
  • 유니코드(UTF-8) : ANSI 부분은 똑같이 1바이트(8비트), 유럽문자는 2바이트, 아시아문자는 3바이트 등으로 가변 표기하는 유니코드. 문서의 용량을 절약하고, 영문 문서와의 호환성을 키울 수 있다.
  • KB : 1024B
  • MB : 1024KB
  • GB : 1024MB
  • TB : 1024GB

16진법

이진법은 컴퓨터가 이해할 수 있는 표현 방식이지만, 인간에게는 너무나 알기 어려운 방식입니다. 하나하나 쓰다가 실수하기도 쉽습니다. 그래서 좀더 인간에게 친숙하면서 컴퓨터와도 친숙한 중간 단계의 표현방법이 있는데, 바로 16진법입니다. 16진법은 0부터 9 그리고 a,b,c,d,e,f 총 16가지의 문자를 사용합니다. 0부터 15까지는 한 자리로 표현되고, 16이 되면 자리를 올려야 하는 표현 방식입니다.

10진수 16진수 2진수
0 0 0000 0000
01 01 0000 0001
02 02 0000 0010
... ... ...
09 09 0000 1001
10 0A 0000 1010
11 0B 0000 1011
12 0C 0000 1100
13 0D 0000 1101
14 0E 0000 1110
15 0F 0000 1111
16 10 0001 0000
17 11 0001 0001

16진법은 어디에 좋을까요? 2진수를 쉽게 변환하여 축약해서 보여줄 수 있습니다. 컴퓨터 파일을 우리가 들여다보고 싶을 때 0과 1이 끝없이 나열되어 있는 것을 보기보다는 16진수로 압축된 수의 나열을 보는 것이 훨씬 보기 좋을 것입니다.

다시 ‘APPLE’이란 문자열로 돌아가 봅시다. 이는 사실 아래와 같이 저장되어 있습니다.

(이진수) 01000001 01110000 01110000 01101100 01100101

이를 좀더 인간 친화적으로 만들려면 아래처럼 십진수로 바꾸는 방법이 있습니다.

2진수 0100 0001 0111 0000 0111 0000 0110 1100 0110 0101
10진수 65 112 112 108 101

그러나 이러한 변환은 무척 시간과 노력이 들어가는 일입니다. 인간에게도 그렇지만 컴퓨터에게도 그렇습니다. 그래서 컴퓨터는 파일의 실제 내용을 보여주고 싶을 때면 이진숫자열을 16진수로 바꾸어서 보여주곤 합니다.

2진수 0100 0001 0111 0000 0111 0000 0110 1100 0110 0101
16진수 4 1 7 0 7 0 6 C 6 5

즉 각 8비트 숫자열은 4비트씩 끊어서 아래와 같은 2자리의 16진수로 표현됩니다.

(16진수) 41 70 70 6C 65

16진수는 2진수 네 자리씩 끊어서 변환하면 기계적으로 간단하게 변환되며, 10진수와의 상호변환도 상대적으로 간단합니다. 예를 들어 195를 16진수로 바꾸어 봅시다.

195 ÷ 16 = 12 ... 3
즉, 195(10) = C3(16)
C3 = 12×16 + 3 = 192 + 3 = 195
즉, C3(16) = 195(10)

테스트를 해볼까요?

  1. 10진수 232는 16진수로 얼마일까요?
  2. 16진수 EE는 10진수로 얼마일까요?
  3. 16진수의 나열 48 65 6C 6C 6F 로 표현되는 문자열은 무엇일까요?
  4. 십진수 65는 이진법으로 바꾸면? 01000001. 16진법으로 바꾸면?
  5. 이진수 01001010은 십진법으로 바꾸면? 82. 16진법으로 바꾸면?
  6. 16진수 B3을 이진법으로 바꾸면? 10110011. 십진법으로 바꾸면? 179
  7. 4비트로 표현 가능한 수 경우는? 0~15. 16가지
  8. 알파벳 대문자를 표현하기 위해 필요한 최소한의 비트수는?
  9. 십진수 82는 ASCII 코드에 의해 어떤 문자로 변환되는가?
  10. ‘Computer’라는 문자열은 ASCII 코드에 의해 어떤 수열로 변환되는가?

음수의 표현

4비트로 표현 가능한 수는 기본적으로 0부터 15까지 16가지입니다. 표현할 수 있는 최소의 수는 0입니다. 8비트로 표현 가능한 수는 0부터 255까지 256가지로, 표현할 수 있는 최소의 수는 마찬가지로 0입니다. 음수를 표현할 수 있는 방법이 없을까요?

가장 간단한 방법은 첫 번째 비트를 + 또는 –를 정해주는 자리로 사용하는 것입니다. 3비트를 이용해 한 번 살펴봅시다.

011 +3
010 +2
001 +1
000 +0
100 -0
101 -1
110 -2
111 -3

그런데 위의 방법을 사용하면 0을 표현하는 이진숫자열이 중복되네요. 게다가 -2+1을 위의 방식으로 표현한 숫자열을 이용해 단순 계산하면

110 -2
+001 +1
111 -3

위와 같은 이상한 결과가 나옵니다. 따라서 만약 위와 같은 음수 표현을 이용해 계산을 할 때에는 덧셈기를 새로 만들어야 하는 단점이 있습니다. 0을 중복해서 표현하지도 않고, 기존의 덧셈기를 그대로 활용할 수 있는 그런 표현 방법은 없을까요?

다음을 생각해봅시다. -1은 음수 중에서 가장 큰 수입니다. 그렇다면 맨 앞자리에 1을 쓸 때 음수를 표현하기로 하는 규칙을 그대로 둘 경우, -1을 포함한 음수들은 아래처럼 표현되는 것이 가장 직관적으로 쓸 만한 방식일 것입니다.

-1 111
-2 110
-3 101
-4 100

어떻습니까? 이렇게 두면 3개의 비트를 이용해 –4부터 3까지 중복 없이 8가지의 수를 표현할 수 있게 됩니다.

011 : +3 010 : +2 001 : +1 000 : 0 111 : -1 110 : -2 101 : -3 100 : -4

위와 같은 음수 표현 방식을 2의 보수를 이용한 음수 표현이라고 합니다. 그게 무슨 뜻이냐면 x와 –x를 더하면 원래는 0이 되겠죠? 이를 흉내내어 3비트의 수에서 x와 더하여 4비트 수인 1000이 되도록 만드는 수를 –x의 이진 표현으로 간주하는 것입니다. 그 수를 x의 (2의) 보수, 라고 부릅니다. 한번 연습을 해볼까요?

001의 (2의) 보수는? 111

001

+111


1000

010의 (2의) 보수는? 110 011의 (2의) 보수는? 101

이런 방식에 따르면 기존의 덧셈이 상당 부분 그대로 적용됩니다.

111 : -1

+010 : +2


1010 : +1

이제 연습을 마쳤으니, 4비트의 숫자열을 이용해 양수와 함께 음수를 2의 보수로 표현한다면, 그 때 표현할 수 있는 수의 범위는 어떻게 될까요? -8부터 +7까지 16가지. 이런 표현 방식을 사용하면, 가장 큰 양수에서 1을 더한 수는 가장 작은 음수가 되는 순환식 구조를 가지게 됩니다.


8비트로 표현할 수 있는 부호 있는 수의 범위는? -128부터 127까지 256가지.


이제 마지막으로 테스트를 해보기 전에, 임의의 양의 이진수에 대한 2의 보수를 쉽게 구하는 방법을 알려드리겠습니다. 가장 널리 알려진 방법은 1의 보수를 구한 뒤 2의 보수로 변환하는 것입니다.

예를 들어 126의 2의 보수를 구해보도록 하겠습니다. 126의 이진수는 01111110입니다. 이 이진수의 2의 보수는 아래의 절차에 의해 구해집니다.

11111111
 -01111110

10000001 (1의 보수)

+00000001


10000010 (2의 보수)

즉 각 자리의 숫자에 대해 0은 1로 1은 0으로 모조리 바꾼 후, 1을 더하는 것입니다.

그럼 간단한 테스트를 해볼까요? 1) 8비트 이진 표현에서, 99는 어떻게 표현될까요? 2) 8비트 이진 표현에서, -99는 어떻게 표현될까요? 3) 8비트 부호 있는 이진 표현에서, 11111000은 십진수로 얼마일까요?

4. 휴식 (50:00-60:00)

5. ANSI, 유니코드, UTF-8 (60:00-80:00)

한글은 어떻게 표현할 수 있을까요? 256가지의 문자만을 표현할 수 있는 ASCII 코드로는 표현이 불가능합니다. 좀더 확장된 코드표가 필요합니다. 과거 많은 나라에서는 ASCII 코드를 확장하여 각 나라의 문자를 표현하는 방법을 강구했습니다. 이를 그냥 ANSI 코드라고도 하며, 각 나라의 확장된 부분의 이름을 따서 EUC-KR, EUC-JP 등의 이름을 붙이기도 했습니다.

예를 들어 ‘AB가나’와 같은 문자열을 ANSI 형식으로 저장하면, A와 B와 같은 알파벳은 ASCII 코드에서 할당된 1바이트를 사용하고, ‘가’와 ‘나’와 같은 문자는 확장된 코드표에서 할당된 2바이트를 사용하는 것입니다. 그래서 ‘AB가나’만 있는 텍스트 파일을 저장하면 실제로는 아래와 같이 저장됩니다.

A B 가 나 41 42 B0 A1 B3 AA

그래서 파일의 용량을 살펴보면 4바이트가 아니라 6바이트가 됩니다. 그런데 만약 우리가 영문과 한글뿐 아니라 히브리어나 아랍어를 한 문서에 작성하고 싶다고 해봅시다. 예를 들어 아래의 문자열을 저장하고 싶다고 해봅시다.

AB가나معنا

이를 한글형 ANSI 확장 코드표인 EUC-KR로 저장하려고 하면 아랍어 부분이 깨지게 되고, 아랍어식 ANSI 확장 코드표인 Arabic (Windows) 등으로 저장하려고 하면 한글 부분이 깨지게 됩니다. 각각의 코드표마다 표현할 수 있는 문자에 한계가 있기 때문입니다. 물론 한국에서는 한글과 아랍어가 함께 포함된 문서를 작성할 필요가 거의 없지만, 만약 한글-아랍 사전이라도 작성하려고 하면 이는 큰일이 됩니다. 이를 어떻게 해결하면 좋을까요?

그 해결책이 바로 유니코드입니다. 데이터가 인코딩 방식에 따라 다르게 보이는 문제를 해결하기 위해서 “모든 문자에 유일한 값을 배정하자”는 개념이지요. 이 유니코드에서는 한 문자를 표현하는 데 더 많은 비트가 필요하게 됩니다. 그래서 텍스트 파일을 유니코드(UTF-16)로 저장하면, 모든 문자는 2바이트씩 할당되어, 그 파일은 실제로는 아래와 같이 저장됩니다.

(BOM) A B 가 나 معنا FF FE 41 00 42 00 00 AC 98 B0 45 06 39 06 46 06 27 06

8개의 문자가 표현되는 데 16+2바이트가 사용되었네요. 다소 낭비가 있는 편이지요. 그래도 세계에 존재하는 수많은 문자를 중복없이 할당하기 위해서는 많은 비트수가 필요할 것입니다. 사실 16비트로도 모자라기 때문에 16비트 안에 표현되지 않는 희귀한 문자는 16비트 두 개로 표현되기도 합니다. 다만 우리가 사용하는 많은 문자들은 그 16비트 안에 들어 있기 때문에 모든 문자가 2바이트로 표현되는 것처럼 보이게 됩니다.

그런데 앞의 FF FE는 왜 있는 것일까요? 이 텍스트 파일이 유니코드 리틀 엔디안으로 인코딩되어 있다는 것을 알려주기 위함입니다. 이러한 표식을 바이트 순서 표식(Byte Order Mark, BOM)이라고 합니다. 문서의 종류가 무엇인지를 알려주는 가장 기본적인 헤더에 해당합니다. 혼란이 없는 경우엔 BOM이 생략되기도 합니다.

16비트 수는 8비트씩 끊어서 저장되게 되는데요. 여기서 리틀 엔디안은 16비트 숫자열이 저장될 때, 아래의 8자리가 먼저 저장되는 경우를 말합니다. 반대로 16비트 이진숫자열에서 아래의 8자리가 나중에 저장되는 경우는 빅 엔디안이라고 합니다. (실제 수를 생각하면 빅 엔디안이 더 인간의 직관에 부합합니다만, 기계에 따라 더 편한 방식을 채택하는 것입니다.) 그래서 위의 문자열을 유니코드 big endian 형식으로 저장하면 아래처럼 저장됩니다.

(BOM) A B 가 나 FE FF 00 61 00 62 AC 00 B0 98

실제로는 B가 A보다 1이 더 큰 값으로 저장되는 것입니다. 한글의 경우, 어떤 순서로 코드가 정해져 있는지 보려면 ‘가각갂갃간갅’을 유니코드 big endian 형식으로 저장해서 살펴보면 됩니다.

(BOM) 가 각 갂 갃 간 갅 FE FF AC 00 AC 01 AC 02 AC 03 AC 04 AC 05

다음 차례는 AC06으로 ‘갆’입니다. 어쨌든 유니코드로 저장을 하면 영문, 한글 상관없이 모든 문자는 2바이트씩 취급되고, 맨 앞에 2바이트의 헤더가 붙어서, 총 용량은 유니코드 텍스트 파일의 용량은 (글자수+2)바이트가 됩니다.

이제 최근 국제 웹페이지에서 가장 많이 사용하는 형식인 유니코드(UTF-8)을 살펴보도록 하겠습니다. UTF란 Universal Transformation Format의 약자로, UTF-16은 유니코드를 16비트씩 끊어서 표현하는 것이고, UTF-8은 유니코드를 8비트씩 끊어서 표현하는 것입니다. 유니코드(UTF-8) 인코딩 형식은 영문을 비롯한 기존 ASCII 부분은 1바이트, 유럽문자는 2바이트, 아시아문자는 3바이트로 표현하도록 만든 코드표입니다. 이를 통해 파일의 용량도 절약하고, ASCII와의 호환성도 높일 수 있습니다. UTF-8 역시 유니코드이기 때문에 세계에 존재하는 모든 문자를 중복 없이 표현할 수 있습니다. 예를 들어 ‘AB가나’를 UTF-8로 저장하면 아래와 같이 저장됩니다.

A B 가 나 61 62 EA B0 80 EB 82 98

텍스트 파일의 용량은 8바이트가 될 것입니다. UTF-8 인코딩 방식에서는 엔디안 문제가 일어나지 않기 때문에 BOM을 붙여야 할 필요는 없지만, 보통은 문서가 UTF-8로 저장되었다는 것을 명시적으로 알리기 위해 3바이트의 BOM을 붙입니다. 그래서 그렇게 저장하면, 아래와 같습니다.

(BOM) A B 가 나 EF BB BF 61 62 EA B0 80 EB 82 98

이 텍스트 파일의 용량은 11바이트가 될 것입니다.

하나의 컴퓨터 텍스트 문서는 문서를 작성할 때 사용된 코드표를 통해서 변환되어야만 정상적으로 우리 눈에 보이게 됩니다. 만약 작성할 때 사용된 코드표가 아닌 다른 코드표를 이용하여 변환할 경우 그 문서는 엉뚱한 문자들로 가득하거나 깨져보이게 될 것입니다. 한번 아무 홈페이지나 들어가서 encoding 옵션을 바꾸어 봅시다. 거의 대부분의 문자가 깨져보이게 됩니다. 다시 말해 컴퓨터에 의해 저장된 문서는 특정한 코드표에 의해 인코딩(암호화)되어 있습니다. 그 문서를 우리가 보기 위해서는 똑같은 코드표를 이용해 디코딩해야만 합니다. 만약 다른 코드표를 이용해 디코딩하면 문서는 깨지게 됩니다. 코드표는 우리의 커뮤니케이션을 위한 기본적인 약속입니다. 이 약속을 어기면 아무런 의사소통도 불가능하게 됩니다.

인간의 문서 -(인코딩)-> (컴퓨터 문서) -(디코딩)-> 인간의 문서

많은 웹페이지에서 코드표를 바꾸어도 신기하게도 영문과 숫자는 깨지지 않습니다. 그 이유는 무엇일까요? 거의 모든 코드표에서 영문과 숫자가 있는 ASCII 부분의 코드를 공유하기 때문입니다.

유니코드와 ANSI 확장 코드의 가장 큰 차이점은 무엇일까요? 하나의 문서 안에서 아랍어, 중국어, 한글, 일본어, 히브리어 등이 함께 쓰여질 수 있으면 그 문서는 유니코드 방식으로 인코딩 되었다고 할 수 있습니다. 반면 ANSI 확장 코드의 경우엔 다양한 문자 중 일부밖에 표현할 수 없습니다. 아랍어를 표현하려면 아랍어 고유의 ANSI 확장 코드를 사용해야 하는데 그러면 한글을 표현할 수 없고, 한글을 표현하려면 EUC-KR 등의 한글 고유의 ANSI 확장 코드를 사용해야 하는데 그러면 아랍어를 표현할 수 없습니다.

유투브와 같은 세계적인 사이트에서, 수많은 언어를 사용하는 사람들이 작성된 페이지를 제대로 읽고 여러 언어로 댓글을 달 수 있으려면 그 페이지는 당연히 유니코드를 사용해야겠지요? 그런 사이트들의 인코딩 옵션을 살펴보면 모두가 Unicode(UTF-8)로 설정되어 있음을 알 수 있을 것입니다.

6. 용량의 단위 (80:00-110:00)

지금까지 다른 텍스트 문서의 용량은 기껏해야 몇 바이트입니다. 쉽게 생각해서 텍스트 문서의 용량은 문자의 수로 정해집니다. 인코딩 방식에 따라 용량의 차이가 있긴 하지만, 용량은 기계적으로 정해집니다.

그런데 우리가 다루는 많은 문서 파일들은 보통 몇 백 KB가 됩니다. 이유는 무엇일까요? 서식이 포함되어 있기 때문입니다. HTML 문서이든, HWP 문서이든, DOC 문서이든 고유의 방식으로 서식을 표현합니다. 서식을 표현하기 위해 실제 텍스트보다 많은 텍스트를 사용하게 됩니다. 실제 우리가 컴퓨터로 다루는 많은 파일들 역시 0101 덩어리에 불과합니다. 다만 형식이 다를 뿐이죠.

KB는 몇 Byte? 1024 B. 보통의 문서 파일들이 이 정도 크기를 가집니다. 웹에서 다운 받을 수 있는 사진들도 몇 십에서 몇 백 킬로바이트의 크기를 가집니다.

그 다음의 단위는 무엇일까요? 네 MB입니다. Mega는 일반적으로 백만의 뜻을 가집니다만, 여기서는 1024*1024의 뜻으로 사용됩니다. 그래서 1 MB = 1024 KB입니다. MB 용량을 가진 것은 어떤 것이 있을까요? mp3 파일이 몇 메가바이트입니다. 고해상도의 사진도 몇 메가바이트의 용량을 가집니다. 과거 플로피디스크는 1.44 메가바이트의 용량을 가졌지요. CD 한 장의 크기는 얼마 정도인가요? 650~700MB입니다.

KB보다 한 단계 큰 단위는 무엇일까요? GB입니다. 역시 1 GB = 1024 MB입니다. 한 자리 기가바이트의 용량으로 표현되는 것은? 메모리(RAM), 메모리스틱, DVD, 블루레이 디스크 등. 어떤 파일이 이런 크기를 가지나요? 동영상. 영화. 커다란 프로그램. 요즘 하드 디스크는 어느 정도 용량을 가지나요? 몇 백 기가바이트. 때로는 테라바이트를 넘어섭니다.

1 TB = 1024 GB입니다. 1 테라바이트는 엄청나게 큰 용량처럼 보이지만, 여기에 들어갈 수 있는 고해상도의 영화는 고작해야 몇 백 개 정도입니다.