반응형

소수(0.1같은 것)를 어떻게 표현할까?

컴퓨터가 실수를 저장하는 법에 대해 알아보자.

 

0. fixed point number

떠오르는 한가지 방법은 정수를 그냥 소수처럼 쓰는 것이다.

예를 들면 시간을 나타낼 때

1초는 1000밀리초니까,

0.001을 1이라고 표기하는 방식이다.

1.1 = 1.100 => 1100

25.200 => 25200

1234.567 => 1234567

이렇게 숫자를 표기하는 방식을 fixed point number라고 한다.

소수점의 위치가 항상 고정이기 때문에 fixed point라는 이름이 붙었다.

그러나 이런 방식은 큰 단점을 가진다.

사실상 정수를 표현하는 것과 다름 없기 때문에 정수형의 범위와 같은 제약을 받는다.

예를 들면, 4byte int형이 -2147483648 ~ 2147483647의 범위를 가지므로

위의 0.001 단위에서는

-2147483.648 ~ 2147483.647

밖에 표현할 수 없게 된다.

 

1. floating point number

따라서 다소 정확성을 잃더라도 좀 더 넓은 범위의 실수들을 저장하기 위하여 floating point, 즉, 부동 소수점이라는 방식으로 실수를 나타낼 수 있다.

다들 중학교 때 배운적이 있을 유효숫자와 지수를 이용하여 숫자를 표현한 방법을 떠올려보자.

 

1234 = 1.234 * 10^3

0.065 = 6.5 * 10^(-2)

 

이 방법을 이용하여 실수를 표현한다면 0번의 고정 소수점보다 더 크거나 작은 수들을 표현할 수 있을 것이다.

 

이 방법으로 실수를 표현하기 위해서는

부호

지수

유효숫자

를 나타낼 필요가 있다.

 

이 모든 비트들을 합쳐서 8비트에 저장한다고 하면

부호 - 지수 - 유효숫자

1비트 - 3비트 - 4비트

정도로 나타낼 수 있을 것이다

 

그럼 이제 각 부분이 어떻게 구성되는 지를 알아보자.

<부호>

실수의 부호에는 음과 양이 있다.

양수는 0

음수는 1

 

<지수>

지수는 몇개를 표현할 수 있을까?

3비트니까 일단 8가지의 지수를 표현해야할 것이다.

그런데 지수비트들이 000인 (모두 0인) 것은 절대값이 작은 소수들을 위해 예약되어있다.

(111 또한 무한대 혹은 NaN - 후에 설명- 을 위해 예약되어 있다.)

따라서 001부터 110까지 7가지를 지수들을 표현하는 데에 쓸 것인데,

지수에는 양수뿐만 아니라 음수도 존재하기 때문에

음의 지수 3개, 양의 지수 3개를 표현하게 된다.

 

그러나 이 부분을 일반적인 정수형의 음수를 사용하지 않고

 bias라는 것을 사용하여 지수를 표현한다.

 

bias는 다음과 같이 정해진다.

2^(b-1)-1

(b가 지수비트의 길이일 때)

우리의 예시에서는 지수비트가 3비트이므로

2^(3-1)-1 = 3

 

지수파트의 비트들에 bias를 뺀 값이 실제 지수이다.

 

무슨 말이냐 하면, 6-3 = 3

1-3 = -2

-2부터 3까지의 지수를 표현할 수 있다는 의미이다.

 

<유효숫자>

유효숫자 부분은 쉽다.

그냥 유효숫자를 생각하면 된다.

다만 2진수의 실수에서 유효숫자의 첫자리(정수자리)는 반드시 1이 되므로 1은 생략하고 소수부분만 적는다.

예를 들어

십진수로 1.5는 1+1/2 이므로

1.100000

앞에 1.을 떼고 유효숫자가 4비트이므로

1000

으로 저장된다.

 

이제 실제 숫자를 저 형태로 만들어보자.

3.5를 생각해보자.

 

먼저 2진수로 바꾸는 작업을 하자.

3.5 = 1.75 * 2 = (1+1/2+1/4) * 2

1.110 * 2^1

 

부호 : 양수이므로 0

지수 : x-3 = 1이므로 x = 4 = 100(2)

유효숫자 : 1.1100에서 1100만 딴다

 

종합하면

0 100 1100이 3.5가 되는 것이다.

 

다음은 좀 더 현실적인 예시이다.

파이의 값을 근사하였다.

 

2. 범위

아까 처음에 봤던 고정 소수점 방식에서 4바이트인 int형을 사용한 소수표현 방식은

10진수로 유효숫자가 9.2자리정도 (첫자리는 1,2만 가능하므로)

소수점은 9칸부터 1칸까지 표현할 수 있다.

 

그렇다면 같은 4바이트에서 실수형은 얼마나 많은 수들을 표현할 수 있을까?

4바이트 = 32비트에서 각 비트들은

부호 - 지수 - 유효숫자 순으로

1비트,  8비트, 23비트를 차지한다.

유효숫자가 23비트인데 이를 10진수로 변환하면 약 7.2자리
지수는 -126승부터 127승까지 표현할 수 있다.
 
0.000000000000000000000001 같은 숫자도 표현할 수 있고 1284371289379812739 같은 숫자도 표현할 수 있다는 말이다.
 
하지만 사실 이 말은 틀렸다.
0.000000000000000000000001의 경우에 이를 2진수로 표현하면 유효숫자가 한자리가 아니라 엄청 길 수도 있다.
1284371289379812739 와 같은 수도 마찬가지이다.
 
0.000000000000000000000001 은
0.00000000000000000000000100000001954148137826... (무한소수)로 저장되고
 
1284371289379812739 은
1284371280803397632 로 근사되어 저장된다.
 
즉, 유효숫자의 범위에 벗어나는 부분의 정확성은 보장되지 않는다.
 
하지만 소수 같은 경우 저정도의 오차는 용납을 하거나 혹은 4바이트가 아닌 8바이트 혹은 16바이트짜리에 실수를 저장하여 (16바이트의 경우 유효숫자가 최대 34자리 정도까지 됨) 정확성을 높이고 있다.
 
3. 특수한 값
앞에서 지수 비트가 모두 0이거나 1인 영역은 예약이 되어있다고 했다.
지수비트가 모두 0이고 유효숫자비트도 모두 0인 수는 0으로 정의되어있다.
그 외에 지수비트가 모두 0이지만 유효숫자가 0이 아닌 수들은 더 작은 값들을 쓰는 데 사용한다.
하지만 이 값들을 사용하면 오차의 발생이 큰 영향을 미칠 수 있다.
 
이 값들을 계속 만지고 놀다보면 유효숫자가 0에 가깝던 놈이 어느 순간 아예 0이 되어버리는 경우가 생기는데,
이러한 경우를 언더플로우라고 한다.
0.000000000000001 이 0이 되어버렸다 이기야.
 
반대로 모든 지수, 유효숫자 비트가 1이면 무한대를 의미한다.
그 외의 경우에는 NaN이라고 해서, Not a Number (숫자가 아니다)라는 특수한 신호를 나타내는 역할로 쓰이고 있다.
인터넷에서 간혹 잘못 코딩된 사이트를 이용할 때 NaN이라는 문구를 본 적이 있을 것이다.
 
-끝-
post normalize 개념은 생략하도록 하겠다.
그 외에 더하기 빼기 곱하기 나누기 등이 어떻게 이루어지는지 fpu랑 관련된 이야기도 생략하도록 하겠다.
 
3줄 요약
1. 부호
2. 지수
3. 유효숫자
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기