[컴퓨터 구조] 문자 및 정수, 부동 소수점 인코딩
컴퓨터는 단지 숫자다
영화 매트릭스에서는 매트릭스라는 가상 프로그램이 초록색 0과 1이라는 숫자의 비가 되어 화면을 흐른다. 컴퓨터를 이루는 가장 기초가 되는 게 무엇인지 차례차례 내려가보면 0과 1이라는 두 수에 도달하게 된다. 0과 1이라는 수는 어셈블리어를 만들고 cpu 로직을 만들고 운영체제와 컴파일러, 다양한 프로그래밍 언어를 만들고 생물과 무생물, 동물, 식물, 기계, 건물과 같은 상위 클래스에서 하위 클래스를 만들고 세상을 이루는 수 많은 건물, 동 식물, 기계 객체를 만들고 결국에 네오라는 객체를 만들어 매트릭스 세상에 집어 넣는다.
0과 1이라는 수가 어떻게 이렇게 끝내주는 세상을 창조할 수 있을까. 몇 백년전 처음 주판을 대신하는 전자 계산기가 나오고 나서, 앨런 튜링이 만든 커다란 계산기면서 최초의 컴퓨터가 나오고 그 이후로는 수 많은 컴퓨터 이론과 하드웨어, 소프트웨어가 은하수의 별처럼 쏟아져 나왔다.
아마 컴퓨터나 전기 공학과를 전공하지 않은 일반인이라면 전자 계산기가 생기고나서부터 이후에 어떻게 컴퓨터가 발전할 수 있었는지 잘 모를거다. 어쩌면 마법과 같은 존재가 되고 있는지도 모르겠다. 인공지능과 딥러닝이 세상에 알려지면서 사람들은 컴퓨터와 더 가까워지는데 훨씬 더 무지한 상태가 되어왔다.
컴퓨터를 구성하는 하드웨어 수준으로 내려가게 되면 전자를 담을 수 있는 하나의 작은 셀안에 얼마나 전자가 있는지가 0과 1을 결정하게 된다. 전자가 얼마나 있는지는 자연속에 존재하는 아날로그로 표현되는 연속되는 값이지만 컴퓨터는 이 값이 일정 기준을 넘으면 1로 넘지 못하면 0으로 바꾸어 간단한 값으로 바꾸어 해석한다. 이렇게 아날로그값을 디지털값인 0과 1로 바꾸는 것이 컴퓨터와 자연을 그토록 다르고 이해하기 어렵게 만든다.
비트란
0과 1 수를 담을 수 있는 공간을 1비트라고 한다. 하나의 비트는 의미가 없지만 여러 개의 비트의 나열을 통해서 정보를 표현할 수 있다. 이 때 컴퓨터가 사람의 개념을 여러 개의 비트에 어떻게 저장할까를 정하는 약속을 인코딩이라고 한다.
- 3과 7과 같은 양수를 표현하기 위한 2진수 체계의 인코딩 방식
- “a, #, ㅎ” 과 같이 사람이 사용하는 문자와 특수기호를 표현하기 위해 약속한 인코딩 방식
- 그리고 정수를 표현하기 위한 인코딩 방식
- 1.324와 같은 소수를 표현하는 부동소수점 인코딩 방식등이 있다.
하지만 여러 가지 인코딩이 혼재한다면 컴퓨터는 어떻게 어디서부터 어디까지가 양수 인코딩인지 문자 인코딩인지 부동소수점 인코딩인지 구분할 수 있을까.
1.문자와 숫자 표현하기
문자 인코딩
우리가 쓰는 언어를 컴퓨터의 1과 0으로 바꾸는 방법을 약속한 것을 인코딩이라고 앞에서 말했다. 문자를 인코딩하는 방법은 크게 ASCII(아스키) 방식과 Unicode(유니코드) 방식으로 나눌 수 있다. ASCII는 아스키라고 읽고 아스키는 가장 자주쓰는 언어인 영어 알파뱃과 특수문자들을 정의한 인코딩 방식으로 총 128개의 문자를 컴퓨터 숫자로 정의해 놓았다. 영어만으로 모든 언어를 표현할 수 없기 때문에 유니코드는 한국어, 일본어, 말레이시아어와 같이 전 세계 모든 언어를 다룰 수 있게 약속한 인코딩 방식이다.
밑에 살펴보면 아스키 코드는 총 128개의 문자를 컴퓨터 숫자로 어떻게 저장할 수 있는지 알려주고 있다.
그렇다면 숫자는 어떻게 표현할 수 있을까
비트의 자리수
컴퓨터에서 다루는 것은 오로지 0과 1를 저장하는 비트의 연속이기 때문에 8비트를 1바이트로 블록처럼 묶어 다룬다고 했다. 01110111
이라는 1바이트 수에서 알아볼 것이 있다. 십 진수를 표현할 때 우리는 1의 자리 10의 자리 100의 자리라고 자리수를 표현한다. 하지만 컴퓨터에서는 관심의 대상인 바이트 배열에서 가장 왼쪽에 있는 비트는 MSB(Most Significant Bit)라고 부르고 가장 오른쪽에 있는 비트를 LSB(Least Significant Bit)라고 부른다.
숫자 인코딩
비 부호형 인코딩
0,1,2,3,4
와 같이 0을 포함한 양수를 컴퓨터에서는 비 부호형이라고 부른다. 수학시간에 양수에는 +를 붙이지 않아도 되듯이 부호가 없이도 읽고 표현할 수 있다는 뜻이다. 비 부호형 정수를 표현하는 방법은 수학시간에 배운 이진수를 표현하는 방식와 동일하다. 0011
은 0 x 2^3 + 0 x 2^2 + 1 x 2^1 + 1 x 2^0 = 3.
부호형 인코딩
부호형 인코딩을 공부하려면 2의 보수라는 개념을 알고 와야 한다.
2의 보수
그렇다면 부호형 정수를 표현하는 방법은 어떤 것이 있을까. 처음에 컴퓨터 과학자들은 이런 생각을 했다. 8비트의 수가 있다면 0111 1111
MSB 즉 가장 왼쪽에 있는 비트를 부호로 사용하면 어떨까? 0은 +
로 생각하고 1은 -
로 생각하는 것이다. 아주 간단한 방법이지만 문제가 있다. 0000 0000
= 0, 1000 0000
= 0, 0을 가르키는 방법이 2개가 되어 낭비되는 표현이 발생하는 것이다. 이 때문에 부호형 정수를 표현하기 위해서는 새로운 인코딩 방식이 필요했는데 이를 2의 보수라고 한다.
2의 보수 표기법은 부호형 정수 X = Bias + M으로 정의한다.
n = 8비트 부호형 정수를 예로 들어 A = 0000 0000
과 B = 1000 0000
라고 해보자
위의 그림에서 MSB는 왼쪽에서 첫 번째 비트로 부호형 정수에서 Bias를 결정한다. Bias란 MSB를 0일 경우에는 Bias = , MSB가 1일 경우에는 Bias = 이 된다. A의 Bias = 이 되고 B의 Bias = 이 된다.
M은 나머지 n -1 비트의 합으로 위의 정수에서 M = = 0이다.
결국 X = Bias + M = 0 + 0 = 0으로 계산할 수 있다. 8비트 정수의 표현 범위를 살펴보면 Bias는 0 또는 -128이며 M은 0부터 127의 범위를 갖는다. 따라서 X는 -128부터 127까지 범위를 갖는 정수로 총 256가지 정수를 표현할 수 있고 이는 2의 보수를 사용하지 않는 방법보다 1가지 더 많은 정수를 표기할 수 있는 장점이 있다.
011110111 11110000을 어떻게 읽을까
컴퓨터는 8개의 비트를 하나의 블록으로 1 바이트를 저장의 최소 단위로 삼는다. 컴퓨터 구조 관점에서 프로그램은 단순한 바이트의 배열로 볼 수 있다. 우리는 위에서 문자를 인코딩하는 방식과 정수를 인코딩하는 방식을 배웠다. 정수를 표현할 때 4바이트로 표현한다고 하고 문자를 표현할 때 1바이트로 표현한다고 한다면 love라는 단어를 표현하기 위해서는 1 byte x 4 = 4 byte가 필요한 것이다. 255라는 정수를 표현하기 위해서도 4byte가 필요하다. 각 두 개의 데이터는 서로 자료형이 다르지만 바이트 길이가 같다. 이 경우에 바이트 배열로 표현한다면 컴퓨터는 어떤 것이 정수이고 어떤 것이 문자인지 구분할 수 있을까? 예를 들어 다음과 같다 01110111 11110000
을 컴퓨터는 어떻게 해석할 수 있을까?
16진수
컴퓨터가 0과 1만 써서 표현하기 때문에 큰 수의 경우에 꽤나 긴 0과 1의 나열로 표현된다. 이는 사람이 읽기에 힘들기 때문에 컴퓨터에는 0과 1로만 기록될 지라도 큰 수를 다룰 때 사람들이 읽기 쉬운 표현 방법을 생각하게 되었다. 16진수가 바로 그 것인데 10진수에 비해 2의 배수로 표현할 수 있으면서 큰 수도 짧게 표현할 수 있어 자주 쓰이게 되었다.
16진수를 표시할 때는 0x
를 앞에 붙여 명확히 알 수 있도록 한다.
16진수에서는 하나의 자리에 0 ~ 15까지 표현할 수 있어야 하기 때문에 10부터 15까지 한 자리로 읽고 쓸 약속을 정해야 하는데 대문자 알파뱃을 차용했다. A = 10, B = 11, C = 12, D = 13, E = 14, F = 15로 읽는다. 예를 들어 15
= 0xF
. 2진수를 16진수로 표현하는 법은 확실히 편한데 0011 1100
이라는 1바이트를 16진수로 표현하려면 4비트씩 묶어 16진수의 각 자리수로 환산해서 적으면 된다. (2^4 = 16이기 때문이다). 앞의 4비트 0011
= 2 + 1 = 0x3
, 뒤의 4비트 1100
= 8 + 4 = 0xC
. 즉 0011 1100
= 0x3C
가 된다.
고정 소수점
소수를 나타내는 방법중 하나인 고정 소수점은 부호형 정수 표현법과 매우 유사하다. 다만 다른 것은 정수부분을 나타내는 비트와 소수부분을 나타내는 비트를 각각 할당해준 것 뿐이다. 이 방식은 간단하기는하나 표현할 수 있는 수의 범위가 크게 제한적이다. 따라서 컴퓨터는 고정 소수점 방식을 사용하지 않는다.
부동 소수점
컴퓨터는 부동 소수점 방식을 채택한다. 소수 부분과 정수 부분을 엄격히 구분하지 않고 표현한다. 중학교 수학시간에 배운 이 바로 부동 소수점 표기법이다. 부동 소수점은 부호를 제외하면 지수와 가수부분으로 나뉜다. 아래는 32비트(float이라고 부른다) 소수를 부동 소수점 방식으로 표현한 것이다.
부동 소수점 방식은 프로그래밍 언어별로 다르게 표기할 수 있기때문에 IEEE에서 정한 국제 표준이 있다.
IEEE 부동소수점 정의 항목
- 수학적 형식(Arithmetic formats)
- 형식의 교환 (Interchange formats)
- 반올림 규칙 (Rounding rules)
- 연산 (Operations)
- 예외 처리 (Exception handling)
1. 수학적 형식
-1.2345를 부동 소수점 표기방식으로 작성하면 다음과 같다.
-1.2345 =
표준 형식 :
k : 지수부 비트 수
n : 유효부 비트 수
유효부는 가수부라고도 부른다.
조금 복잡해 보이지만 컴퓨터에서 부동 소수점은 위와 같은 형식으로 표현한다. 32비트 크기의 자료형인 Float를 기본으로 설명할 것이다.
S : 는 부호를 표현하기 위한 식으로 S는 MSB 1비트 값이다.
M : 은 유효값을 나타내는 것으로 23개 비트인 n을 사용해서 표기한다.
E : 는 지수값을 나타내는 것으로 8개 비트인 k를 사용해서 표기한다. 지수는 음수와 0도 들어갈 수 있어야 한다. E의 범위는 위에서 설명한 8비트 2의 보수 표현법이 -128 ~ 127까지 범위를 가졌던 것과는 달리 -127 ~ +128의 범위를 가진다. 이 중 -128과 -127은 특별한 경우에 사용된다.
2의 보수 vs Bias
Bias 표현법은 부동 소수점의 지수 파트를 표기하기 위해서 고안된 개념으로 Bias를 이해하는 것이 부동 소수점 이해에 필수적이다. 2의 보수 표현법과는 근소한 차이가 있다.
Bias는 항상 고정된 값을 가진다. Bias = 이며 e는 지수부 k비트를 합한 값으로 표현한다.
-
32비트 float
Bias = = 127
Bias에서 을 사용하지 않고 굳이 값을 사용했는데 이 때문에 E는 -127 ~ +128까지의 범위를 갖게 된다. 정규화에서는 ~ 이 모두 0이거나 모두 1이 되는 경우는 비정규화와 무한대를 표현하기 위해서 남겨놓고 사용하지 않는다. -
2의 보수
0000 0000
: 0
0111 1111
: 127
1000 0000
: -128
1111 1111
: -1 -
Bias 표현법
0000 0000
: -127
0111 1111
: 0
1000 0000
: 1
1111 1111
: 128
2. 형식의 교환 (Interchange formats)
부동 소수점에는 약간의 트릭이 있기때문에 이해하는 데 시간을 들여야 하지만 아래 4가지 내용에 대해서만 이해한다면 완벽히 내 것으로 만들 수 있다. 유효숫자 비트값 f를 짚고 가도록 하겠다.
그림에서 f란 23개 비트를 사용한 이진값이고 소수 첫 번째 자리부터 계산해 합산하기 때문에 1보다 작은 값이다.
각 형식에 따라서 f와 e의 정의는 변동이 없지만 M의 정의는 달라질 수 있다.
CASE 1 : 정규화
- e
- M = 1 + f
- E = e - Bias
정규화란 쉽게 말해서 가장 자주 쓰이는 유형이라는 뜻이다. 대부분의 값들을 이 정규화 형식으로 표현할 수 있다. 정규화와 비정규화가 달라지는 것은 M과 E를 계산하는 식이 다르다.
M은 유효값이라고 말했는데 M이 정규화에서 갖을 수 있는 값은 를 만족해야 한다. 수학시간에 배운 유효값은 을 만족하도록 지수값을 조정했지만 여기에서는 2진수이기 때문에 10->2 가 되었다.
는 지수값을 의미하는데 E = e - Bias로 정의한다. 단 정규화에서 E값이 -127과 128이 되는 경우는 사용하지 않도록 약속한다.
0000 0000
: -127
1111 1111
: 128
위 두 가지 수는 각 비정규화와 Infinity를 위해 남겨둔다.
M = 1 + f라고 정의한다. 항상 M은 1보다 커야 하기 때문에 1보다 작은 f에 1을 더해 유효값이 되도록 한다. 예를 들어 f = 0.9라고 한다면 실제로 유효값은 1.9로 계산하는 것이다. 이 방법은 한 가지 장점이 있는데 1을 표현하는데 드는 한 비트를 아낄 수 있다는 것이다. 만약 M = f라고 정의한다면 f가 1보다 큰 값을 가질 수 있도록 추가적인 비트를 f에 할당하고 새롭게 f를 정의해야 할 것이기 때문이다.
정규화에서 갈라져 나온 아래 3개의 CASE는 모두 예외 케이스로 보는 것이 마땅하다.
CASE 2: 비 정규화
- e
- M = f
- E = 1 - Bias
비 정규화란 자주 쓰이지 않는 특이한 경우를 말한다. 비 정규화에서 e의 모든 비트는 0이 된다. 따라서 e = 0이다. 비 정규화란 특히 정규화로 표현할 수 있는 수의 범위보다 작은 값을 표현하기 위해서 만들었다. 정규화가 표현할 수 없는 값이란 0.0을 예로 들 수 있다. 항상 M = 1 + f로 정의하기 때문에 유효값은 항상 1보다 크기 표시되기 때문에 0을 표시할 수 없다. M = 1 + f였던 정규화와는 다르게 비 정규화에서는 M = f로 정의한다. 따라서 비 정규화 형식은 정규화에서 표현할 수 없는 0을 표현하거나 0에 매우 가까운 값을 표현하는데 사용할 수 있다.
E 또한 식이 달라진다. 정규화에서는 E = e - Bias로 사용했고 이제 e = 0이기 때문에 비 정규화에서 E = 0 -Bias = -Bias 가 되어야 할 것 같지만 비 정규화에서 E = 1 - Bias로 정의한다. 이유는 간단한데 0에 매우 가까운 수를 표기하기 위해서 M 값에 더 이상 1을 더하지 않기로 했는데 이는 지수상으로 1만큼 빼는 효과가 생긴다. 때문에 E 값에 1을 더해줌으로써 이 효과를 상쇄하는 것이다. 아래 예를 통해 살펴보겠다.
가. 0000 0000 0001 0000 ... 0000
:
e 값이 1이기 때문에 정규화. E = -126 f = 0, M = 1.0.
'가’는 정규화 값이 표현할 수 있는 가장 작은 값이다.
나. 0000 0000 0000 1111 ... 1111
:
e 값이 0이기 때문에 비 정규화. E = -126 f = 0.99…, M = 0.99…
'나’는 비 정규화 값이 표현할 수 있는 가장 큰 값이다.
'가’와 '나’의 값을 비교해보면 '가’에서 e = 1이고 '나’에서 e = 0이지만 E의 값은 -126으로 같다. '나’는 등비가 무한등비급수에 가깝기 때문에 약 0.99라고 생각해도 된다. 비 정규화의 E의 값이 -126이기 때문에 정규화 값과 자연스럽게 연결되는 것을 볼 수 있다. 따라서 이러한 표현의 비 정규화는 수학에서 수가 가져야 하는 촘촘한 성질을 최대한 나타낼 수 있는 우아함을 나타낼 수 있다.
부호비트인 s 비트가 0이고, e비트와 f비트도 모두 0을 만족한다면 이므로 을 나타낸다. 여기서 s 비트만 1로 바뀐다면 을 나타낸다. +0.0과 -0.0은 부동소수점 비트상으로는 다른 값이 되는 것이다.
CASE 3: Infinity
- e = 255
- f = 0
때로는 해당 부동 소수점 자료형에 할당된 비트로만은 표현할 수 없을 정도로 절대값이 큰 소수를 표현하라는 요청이 생길 수 있는데 이 경우 Infinity 형식을 사용한다.
이는 을 만족하고 유효값 비트가 모두 0으로 이다. 예를 들어과 같이 큰 수는 정규화의 E가 표현할 수 있는 범위인 127을 넘기 때문에 Infinity로 표현한다. infinity의 f의 모든 비트는 0으로 정의하기 때문에 같은 Infinity라면 수가 얼마나 크든지 부동 소수점 비트상으로 완벽히 일치한다. 다만 s=0이면 s=1이면 로 양과 음은 구별할 수 있다.
CASE 4: NaN
- e = 255
- f
마지막 범주는 NaN이라고 한다. NaN이라는 단어는 Not a Number의 약자로 실수 범위에서 수학적으로 정의하지 않는 값을 가르키기 위해서 정의되었다. f 인 것이 infinity와 구별하게 해준다.
NaN의 부호 비트 s는 어떤 값이든 관계 없고 이고 f비트는 1인 값이 하나라도 있으면 만족한다.
NaN이 발생하는 경우는 다음과 같다.
, | |
, |
NaN은 quite NaN과 signaling NaN으로 나뉜다.
- quite NaN : , 예외를 출력하지 않는다.
- signaling NaN : , 예외를 출력한다. 어떤 정보부터 저장할까
- 리틀 엔디안(little endian)
- 빅 엔디안(big endian)
정리
마지막으로 정리해보면 다음과 같다.
k : 지수부 비트 수
n : 유효부 비트 수(가수부)
Bias =
e =
f =
형식 | f | M | e | E |
---|---|---|---|---|
정규화 | Anything | 1 + f | e - Bias | |
비정규화 | Anything | f | 0 | 1 - Bias |
infinity | 0 | X | 255 | X |
NaN | X | 255 | X |
댓글
댓글 쓰기