1. 소개


정수(Integer) 는 우리가 흔히 알고 있는 0, 1, 2, 3과 같은 숫자이다. 컴퓨터에서 정수는 정확하게 표현된다. 예를 들어, 숫자 ‘2’는 항상 2로 저장되며, 더하거나 빼도 그 값이 정확하게 맞는다. 즉, 정수는 정확성(Accuracy) 이 매우 뛰어나다. 예를 들어, 2 + 1 = 3이 정확하게 나온다.

하지만 정수는 소수점 값을 표현할 수 없기 때문에 정밀도(Precision) 가 떨어진다. 예를 들어, 5 ÷ 2는 2.5이지만, 정수는 소수점을 버리고 2만 저장한다. 이처럼 정수는 소수점 이하의 값들을 무시하기 때문에 작은 차이들을 정확하게 표현하기 어렵다.

그렇다면 어느 순간 소수를 사용해야하는 상황이 있을때, 컴퓨터는 소수를 어떻게 저장하고 사용할까?



2. 소수 -> 이진수


우선, 소수를 이진수로 변환하는 과정부터 알아보자. 0.n으로 표현된 숫자 역시 이진수로 표현 가능하다. 소수 부분이 0이 될때까지 계속해서 2를 곱해주다가, 그 과정에서 소수 에서 정수의 1의 자리 부분으로 올림이 일어나면 1을 기록하고 - 아니면 0을 기록해나간다. 간단한 예시로 살펴보자.

0.25 -> 이진수:

  1. 0.25에 2 곱하기: 0.25 × 2 = 0.5 정수 부분은 0이므로 0을 기록하고, 소수 부분(0.5)을 다음 단계로 넘긴다.

  2. 0.5에 2 곱하기: 0.5 × 2 = 1.0 정수 부분은 1이므로 기록한다. 소수 부분이 0이 되었으므로, 변환을 종료한다.

  3. 결과: 0.25의 이진수 표현은 0.01! 이렇게 0.25는 이진수로 딱 떨어지며, 무한 소수로 이어지지 않는다.

0.1 -> 이진수:

  1. 0.1에 2 곱하기: 0.1 × 2 = 0.2 정수 부분은 0이므로, 기록하지 않고 소수 부분(0.2)을 다음 단계로 넘긴다.

  2. 0.2에 2 곱하기: 0.2 × 2 = 0.4 정수 부분은 0이므로, 기록하지 않고 소수 부분(0.4)을 다음 단계로 넘긴다.

  3. 결과: 계산을 계속 진행해보면 알겠지만… 끝나지 않는다. 즉, 이 경우는 절대로 소수 부분의 값이 0이 되지 않는다. 0.1의 이진수 표현은 0.000110011001100…으로 무한히 반복된다.

대충 견적이 나오는 것 같다. 컴퓨터에서 소수를 다룰 때는 표현의 한계가 있기 때문에, 소수점을 일정한 자리에서 끊어 표현해야 한다. 소수를 표현하는 방법에는 크게 두 가지가 있는데, 고정소수점과 부동소수점 방식이다. 각각의 방식을 하나씩 자세히 알아보자.

3. 고정소수점


고정소수점(Fixed Point) 은 소수점을 고정된 위치에 두고 정수와 소수 부분을 구분하여 숫자를 표현하는 방식이다. 즉, 정수부와 소수부의 자릿수가 미리 정해져 있는 것이 특징입니다. 예를 들어, 소수점 이하 두 자리를 사용할 경우, 12.34와 같은 값을 정확하게 표현할 수 있다! 소수부 자릿수가 고정되어 있기 때문에, 정밀도(Precision) 는 소수부 자릿수만큼만 유지된다. 이 방식은 컴퓨터의 연산 속도가 빠르고 구현이 간단하다는 장점이 있다.

정확성(Accuracy) 측면에서는 부동소수점에 비해 일정한 범위 내에서는 매우 정확한 값을 표현할 수 있다. 소수부의 자릿수가 고정되어 있기 때문에, 표현할 수 있는 값이 제한되지만 해당 범위 내에서 실수 값을 정확하게 다룰 수 있다.

그러나 표현 범위는 제한적이다. 고정된 소수 자릿수 때문에 매우 큰 수나 매우 작은 수를 표현하기 어렵다. 예를 들어, 소수점 이하 두 자리를 사용하는 고정소수점 방식에서 1000.01이나 0.001 같은 숫자를 정확히 표현할 수 없다. 큰 수나 작은 수는 범위를 초과하거나 정밀도가 손실되는 것이다.

정밀도가 떨어지는 정확한 예시

0.1을 고정소수점 방식으로 컴퓨터에 저장해보자. 먼저, 0.1을 이진수로 변환하면 0.000110011001100... 처럼 무한 소수가 된다. 고정소수점 방식에서 32비트 크기를 사용하는 경우, 이를 표현할 수 있는 방법은 제한적이다. 우선 부호는 양수이므로 + 이고, 정수 부분은 0이다. 소수를 표현할 수 있는 비트는 15비트라고 가정하면, 소수점 이하로 반복되는 무한 소수 중 15번째 자리까지만 기록할 수 있다.

이렇게 보면, 고정소수점 방식도 나름 소수점을 잘 기록할 수 있는 것처럼 보일 수 있다. 그러나 부동소수점 방식과 비교해보자. 부동소수점 방식은 소수점의 위치를 가변적으로 옮길 수 있어, 32비트 내에서도 더 많은 소수 부분을 표현할 수 있다. 즉, 소수 부분의 비트를 더 확보하여 고정소수점 방식보다 더 많은 무한 소수 자릿수를 저장할 수 있는 것이다. 물론, 부동소수점 방식도 한계는 존재하지만, 고정소수점에 비해 더 유연하며 정확도가 높은 방법이다.



3. 부동소수점


부동소수점(Floating Point) 은 소수점을 가변적으로 움직여 숫자를 표현하는 방식이다. 이는 숫자의 정수부와 소수부를 나누어 고정된 자리에서 소수를 표현하는 고정소수점 방식과 다르게, 소수점의 위치를 자유롭게 옮길 수 있는 방식이다. 부동소수점은 숫자를 가수(Mantissa)지수(Exponent) 로 나누어 표현한다.


3-1. IEEE-754 표준

부동소수점(Floating Point) 숫자에 대해 설명할 때, 가장 많이 사용하는 표준은 IEEE-754 표준이다. 이 표준은 많은 컴퓨터 시스템에서 부동소수점을 처리하는 방식이므로, 한번 공부해보자.

 seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm : meaning
31                              0 : bit
s = sign(부호) / e = exponent(지수) / m = mantissa(가수)
  1. 부호
  1. 지수
  1. 가수

결국, 123.45라는 숫자가 있다면 1.2345 × 10^2 처럼 표현하는 방식이 부동소수점의 원리이다. 이 방식은 지수를 이용해 소수점의 위치를 표현할 수 있기 때문에 매우 큰 숫자나 매우 작은 숫자를 다룰 때 유용하다.

3-2. 예시 : 45.625

예시로, 숫자 45.625 를 부동소수점 형식으로 변환하는 과정을 살펴보자. 여기서는 부호를 1비트, 지수를 8비트, 가수를 23비트로 사용해자!

  1. 부호: 45.625는 양수이므로 부호는 0이다.

  2. 정규화: 45.625를 2진수로 변환하면, 101101.101이 된다. 이를 부동소수점으로 표현하기 위해 정규화하면, 1.01101101 × 2^5가 된다. 즉, 2진수 형태에서 소수점을 첫 번째 비트 뒤로 이동시켜 1.xx 형식으로 만든 것이다.

  3. 지수(Exponent)와 Bias: 정규화된 값에서 지수는 5이다. IEEE 754 표준에서는 32비트 부동소수점 수의 경우 Bias 가 127이다. 따라서 실제 지수 값은 5 + 127 = 132이다. 이를 2진수로 표현하면 10000100이 된다.

  4. 가수: 가수는 소수점 이후의 부분을 사용한다. 즉, 01101101이 가수 부분에 해당한다. 부동소수점에서는 23비트까지 가수를 표현할 수 있으므로, 빈 비트가 있으면 0으로 채운다. 따라서 가수는 01101101000000000000000이 된다.

결과적으로, 부동소수점 형식으로 45.625를 표현하면 다음과 같다:



4. 편향된 지수?


편향된 지수, 개념이 조금 어려울 수 있지만 한 번 더 살펴보자.

부동소수점에서 지수(Exponent) 는 숫자의 소수점을 왼쪽이나 오른쪽으로 움직여 숫자를 정규화하는 역할을 한다. 예를 들어, 0.0001 이라는 숫자를 부동소수점으로 표현하려면 1.0 × 10^(-4) 로 정규화해야 한다. 이때, 지수 -4 를 나타내야 하는데, 음수 지수를 어떻게 표현할까? 만약 음수를 직접 저장하려면 지수에 음수를 나타내는 비트 를 하나 더 사용해야 할 것 같다. 하지만 이렇게 되면 지수를 표현할 수 있는 비트 수가 줄어들어, 더 작은 범위만 표현할 수 있다는 문제가 생긴다.

이 문제를 해결하기 위해 부동소수점에서는 편향된 지수(Biased Exponent) 방식을 사용한다. 이 방식은 음수 지수양수로 변환 하여 저장하는 방법이다. 이를 위해 편향 값(Bias)을 사용하여 지수 값에 특정 값을 더해 저장하고, 저장된 값을 읽어올 때는 다시 편향 값을 빼서 원래의 지수 값을 복원한다.


4-1. 실제 예시

8비트 지수를 사용하는 경우, 편향 값(Bias)은 127 로 설정된다. 편향 값을 127로 설정하면, 지수를 음수와 양수 모두 표현할 수 있다.

이렇게 음수 지수도 양수로 변환 해 저장할 수 있다. 이를 통해 부동소수점에서는 지수를 저장할 때 양수로만 처리하면서, 지수 표현 범위 를 넓게 유지할 수 있다.


4-2. 지수 범위

8비트로 표현 가능한 값은 0부터 255 까지인데, 편향 값(Bias)이 127 인 경우 실제 지수는 -126에서 +127 까지 표현할 수 있다. 이처럼 편향된 지수를 사용하면 8비트 안에서 음수 지수와 양수 지수를 고르게 분배 할 수 있다.

즉, 편향된 지수를 사용하면 음수와 양수 지수를 하나의 양수 범위 안에 균등하게 포함 시킬 수 있어, 음수 지수를 저장하기 위한 별도의 비트가 필요하지 않다.


4-3. 특수한 경우

0, 무한대, NaN

0

IEEE-754에서 0은 특별한 경우로 처리된다. 가수와 지수, 그리고 부호 비트 모두 0일 때 0으로 간주된다.

+0: 0x00000000 -0: 0x80000000

무한대

지수가 모두 1이고, 가수비트가 모두 0이면 무한태를 나타낸다. 이때 부호비트가 0이면 양의 무한대를, 1이면 음의 무한대를 의미한다.

+∞: 0x7f800000 -∞: 0xff800000

NaN

NaN은 수학적으로 정의 되지 않는 값, 즉 Not a Number 이다. 지수 비트가 보두 1이고, 가수 비트중 하나라도 1이 존재한다면 그것은 NaN의미 한다.

NaN: 0x7fc00000


4-3. 결론

편향된 지수를 사용하는 주요 이유는 지수 값을 비트 수준에서 간단하게 비교 할 수 있게 하기 위함이다. 편향된 지수를 사용하면 모든 지수가 양수 값으로 표현되기 때문에, 두 부동소수점 수의 크기를 비교할 때 지수 부분을 직접 비교할 수 있다.

즉, 지수가 126이면 127보다 작고, 128보다 크다는 것을 간단하게 알 수 있다. 이렇게 하면 연산에서의 복잡성을 줄이고, 비교 연산을 더욱 효율적으로 할 수 있다. 또한, 편향된 지수를 통해 음의 지수도 표현할 수 있게 되어, 매우 작은 수부터 매우 큰 수까지 광범위한 실수 범위를 표현할 수 있다.



5. Reference