정수 음수 표현
Signed Magnitude
이 방식에선 먼저 '부호 비트'를 제외한 수를 양수로 읽는다. 그리고 부호 비트에 따라 양수와 음수를 판단한다.
즉, 수를 절대값으로 생각한 다음, 음수일 경우 - 부호를 붙이는 방식이다.
예를 들면, 0010은 2, 1010은 -2라고 판단한다.
다만 음수를 더하거나 양수를 뺄셈할 때 문제가 생길 수 있다.
위의 두 수 0010과 1010을 더하면 0이 돼야 하지만, 실제론 1100이 된다. 1100을 Signed Magnitude 방식으로 읽으면 -4가 되므로 정확한 계산을 위해선 추가적인 연산이 필요해 비효율적이다.
1의 보수 (1's Complement)
1의 보수 방식은 표현하려는 수의 절대값의 비트들을 반대로 만들어 표현하는 방법이다.
- 5를 표현하려면 5를 이진수로 표현한 0101의 비트를 반전시켜 1010으로 만들어 표현하면 된다.
정석적인 방법은 모든 비트값이 1인 수에서 음수로 표현할 수를 빼면 된다.
0을 표현하는데 두 개의 조합을 사용하기 때문에 효율적이지 못하고 사칙연산에도 오류가 생길 수 있어 안쓰인다.
2의 보수(2's complement)
2의 보수 방식은 1의 보수로 표현된 수에 1을 더하면 된다.
정석은 2^n 에서 표현하려는 수를 빼면 된다.
주어진 자리수보다 1자리를 더 써서 계산해야되는데 사람이 계산하기엔 1의 보수에서 1을 더하는 게 더 쉬운 듯
2의 보수 방식은 1의 보수보다 1개의 수를 더 나타낼 수 있다. 사칙연산도 문제없이 가능하다.
대부분은 2의 보수 방식을 쓴다고 한다.
1의 보수와 2의 보수가 왜 이름이 되었는지 궁금해서 찾아봤는데, n진법을 사용할 때 기수보수를 n의 보수, 감소된 기수 보수를 n-1의 보수라고 쓰는 걸 알게 됐다. 보수 방식을 사용하면 제한된 비트로 표현가능한 수를 양수와 음수로 균형있게 나눌 수 있고 연산에도 편리하기 때문이라고 한다.
고정소수점 방식
고정 소수점 방식은 이름처럼 소수점의 위치를 고정해 두는 방식이다. 앞에서 양수와 음수를 대칭적으로 표현한 것처럼 정수부와 소수부를 대칭적으로 표현하면 된다. 그러면 2의 보수처럼 이 방법도 효율적일까?
고정 소수점 방식은 단점이 치명적이다. 물론 장점도 있다. 고정된 비트 수로 정수부와 소소부를 표현하기 때문에, 계산 과정에서 오차를 최소화 할 수 있어 계산의 정확도가 높은 장점이 있다.아주 큰 수나 작은 수를 표현하기엔 비트가 모자랄 경우가 있기 때문에 표현할 수 있는 수의 범위가 매우 제한적이다. 사용할 수 있는 같은 비트를 쓰면서 표현할 수 있는 수가 적으니 저장공간을 효율적으로 쓰지 못한다는 걸 알 수 있다.
부동소수점 방식
부동 수수점 방식은 소수점을 정해두지 않는다. 부동이면 움직이지 않는 거 아닌가요? 고정이랑 똑같은 거 아닌가? 싶을 수도 있지만 여기서 부동은 떠다닌다는 의미로 생각하는 게 좋다. 영어로도 floating-point다. 부동소수점 방식에선 표현할 수를 정규화를 통해 가수와 지수로 나눈다. 우선 수를 2진수로 변환하고 소수점의 위치를 왼쪽에서 가장 먼저 나오는 1의 오른편에 찍는다. 숫자의 크기에 따라서 소수점은 왼쪽으로 이동할수도 있고 오른쪽으로 이동할수도 있을 것이다. 소수점을 정하면 해당 수의 소수부를 가수, 소수점을 이동시킨 만큼 곱해줄 2^n의 n값을 지수라고 한다. IEEE 754 표준에서는 32비트일 때 부호에 1비트, 지수에 8비트, 가수에 23비트를 사용한다. (IEEE 754는 IEEE라는 아주 대단한 곳에서 정한 기술 표준이다. 대부분의 시스템이 이를 따른다고 하니 우리도 따르자)
소수부가 23비트를 초과할 경우 뒷부분을 잘라내고 모자랄 경우엔 빈자리를 0으로 채운다. 가수는 왼쪽부터 사용하기 때문에 빈자리는 오른쪽 공간을 뜻한다.
8 bit의 지수 자리에 지수를 넣는다. 지수는 양수일 수도 있고 음수일 수도 있다. 그럼 2의 보수를 사용하면 되지 않을까? 방금 배운 게 아쉽게도 IEEE 754 표준에선 Bias를 사용한다. Bias는 편향, 편견 그런 뜻인데 여기선 편향으로 이해하면 좋다. 우리는 지수에 Bias 값을 더해서 사용할 것이다. 이를 매직넘버라고 하는 경우도 있는데, 매직넘버는 보통 선언없이 갑자기 쓰이는 상수를 뜻한다. 가독성도 떨어지고 유지보수에도 불편하고 작성자마저 나중에 왜 이게 100이었지? 할 수도 있다. 다시 돌아가서 Bias 값으로는 2의 지수에 할당된 bit -1승을 쓰거나 그 값에서 1을 뺀 값을 쓴다. 8 비트에선 2의 7승인 128이나 127을 쓴다는 뜻이다. IEEE 754 표준에선 127을 쓰라고 하니 127을 써보자. 우리가 구한 지수에 127을 더해서 사용하면 0~255의 값을 채울 수 있다. 이 말은 우리는 -127~128까지의 지수를 표현할 수 있다는 뜻이다.
부동소수점 방식으로 쓰여진 실수를 읽으려면 반대로 하면 된다. 지수부에 적힌 숫자에서 127을 빼서 지수를 구하고, 가수부에 적힌 수에 1을 더한다음 구한 지수를 토대로 원래 숫자를 구할 수 있다. 부호도 까먹지 말자!
가수부에 1을 왜 더하는걸까? 가수부에 1을 더하는 이유는 우리가 1을 생략했기 때문이다. 우리는 소수부만 가수로 취급했다. 굳이 소수부만 가수로 취급한 이유는 정수부의 값은 당연히 1이기 때문에 굳이 표현할 필요가 없기 때문이다. 1이 항상 존재한다면 굳이 가수에 포함시켜 bit 를 낭비하지 않을 수 있고 우리는 더 많은 소수부를 표현할 수 있게 된다. 2^22개 만큼 말이다.
그렇다면 지수부에는 왜!!!!! 2의 보수를 사용하지 않고 번거롭게 새로운 시스템을 도입했을까?
이게 너무 궁금해서 몇 시간 동안 고민하고 정보를 찾아 봤었다...
우선 범위 표현에 차이점이 있다고 하는데 일단 두 방식 모두 표현할 수 있는 범위도 균형적이고 범위의 크기도 같다. 아까 Bias를 편향이라고 했는데, Bias 방식은 특정한 값을 더해 지수부를 양수로 편향시킨다. 음수인 지수도 Bias가 더해져 0이나 양수가 된다. 하지만 2의 보수는 최상위 비트 값에 따라 부호가 결정되므로 양수인지 음수인지 판단이 필요해진다.
컴퓨터는 어차피 빠르니까 양수 음수 빠르게 구분하면 되는거 아닌가??? Bias를 더하는 작업을 하고 나중엔 빼서 지수를 알아낼테니 Bias 방식이 추가작업이 있는거 아닌가? 2의 보수는 덧셈 뺄셈 잘되라고 만든거니까 좋지 않을까???
실수를 연산할 때 지수부끼리 연산하는 과정에서 두 수의 지수를 맞추기 위해 덧셈과 뺄셈을 할 필요가 있다. 하지만 지수부에서의 연산은 덧셈이나 뺄셈보다는 단순 비교가 더 자주 일어난다. 부호를 처리하는 과정이 필요한 2의 보수 방식과는 달리 Bias 방식에선 지수의 크기만 비교하면 되서 간단하다.
수를 비교하려면 뺄셈을 해서 결과가 양수인지 음수인지 봐야하는 거 아닌가??? 뺄셈을 해야되는데 왜 비교가 덧셈 뺄셈보다 간단하다는 거지???
컴퓨터가 멍청해보여서 덧셈 뺄셈부터 해서 모든 작업을 처리한다고 생각할 수도 있다. 하지만 컴퓨터 하드웨어엔 비교기라는 장치가 있다. 두 숫자를 비교할 때 쓰이는 이 장치는 두 수를 비트별로 비교해 두 수가 같은지, 큰지, 작은지 판단한다.
XOR 게이트 같은 논리 게이트를 통해 두 비트를 비교하는데, 부호 비트부터 비교해 부호가 다르다면 판단을 끝내고, 같다면 다음 비트로 넘어가 값을 비교한다. 첫 번째로 차이가 생기는 비트를 기준으로 대소를 결정한다. 이런 작업을 하는 비교기는 덧셈이나 뺄셈처럼 복잡한 과정 없이 단순히 비트를 비교하는 것만으로 결과를 얻는다. 암튼 비교가 더 간단하다고 한다. 2의 보수 방식도 음수는 부호를 제외한 부분의 절대값이 클수록 실제로 값도 크니까 비트별로 비교하는 게 가능할 것 같은데 부호를 처리하는 데서 효율이 차이난다고 한다. cpu의 alu(산술 논리 장치)에서도 정수 연산을 하는 부분과 실수 연산을 하는 부분이 별도로 존재하기 때문에 정수표현은 2의보수, 실수표현은 bias방식을 쓰는 이유가 납득이 되는 부분이다.
IEEE 754 표준에선 부동소수법으로 표현 시 발생할 수 있는 문제에 대해 예외처리를 해두었다. 부동소수법 표현 시 모든 자리가 0이라면 2의 보수에선 실수의 값이 1이 되고 Bias 방식에선 2의-127승이 된다. 그렇다.. 0을 표현할 수 없는 것이다. 2^-127이란 숫자는 아주 작지만 0은 아니다. 0이 필요할 때 마다 정수를 끌어올 것도 아니고 문제다! 이를 해결하려고 만든 예외가 있다. 지수부분이 모두 0인 경우, 생략된 정수를 1이 아닌 0으로 쓰고 지수는 -126을 쓰기로 했다. 이로써 모든 칸을 0으로 쓰면 0을 표현할 수 있고, 가수가 0이 아니라면 0과 2^-126 사이의 작은 수들을 표현할 수 있게 됐다. 2^-127보다도 작은 수를 표현할 수 있는 것이다. 가수를 최대한 작게 만들면 2^-149까지 표현이 가능하다.
모든 지수가 1이고 가수가 모두 0이라면 무한을 의미하고, 모든 지수가 1인데, 가수는 0이 아니라면 NaN을 의미한다. NaN은 Not a Number라는 뜻이다.
부호부에 따라 양의 무한대, 음의 무한대가 되고 가수부가 모두 1인 NaN은 예외를 발생시키지 않고 연산을 지속시킨다거나 0에도 부호를 구분하지만 오류를 막기 위해 -0 = +0으로 정했다거나 하는 내용도 있지만 공부는 충분히 많이 한 것 같다.
실수끼리 곱할 땐 지수부끼리 더하고 중복된 bias값을 빼주면 된다. 이 때 소수부를 조절해도 표현범위를 벗어난다면 무한이나 0으로 표시하는 것 같다. 덧셈시에는 지수가 큰 쪽으로 지수부를 맞추고, 지수부가 작았던 수는 소수부를 우측으로 미뤄 계산한다. 지수가 큰 쪽으로 맞추는 이유는, 지수가 큰 수가 더 큰 수를 표현하므로 정밀도를 유지하는 데 유리하기 때문이다.
이정도면 Bias 사용하는 이유가 납득은 될 것이다. 우리가 봐도 더 직관적이긴 하지만 주된 이유는 비교 연산과 하드웨어 설계 때문이라고 생각하자.
컴퓨터 과학 지식이 중요한 이유가 이런 것 때문이 아닐까? 학부 1학년 때 배우는 내용이지만 왜? 왜? 왜? 하고 파고들다 보면 하드웨어와도 연결이 되는 게, 소프트웨어만 다루는 개발자여도 컴퓨터가 어떻게 작동하는지 알아야 하는 이유가 아닐까!!!! 머리는 아프지만 미지의 것을 탐구하는 순수과학 보다는 인간이 만들어낸 시스템 안에서 원리와 이유 궁금증을 풀어가는 게 훨씬 괜찮을지도
나중에 보기 좋게 정리해봐야지...