부동소수점 방식의 지수 부분만을 표현하기 위한 정수 표현 방법

실수의 표현

정수를 표현하는 방법을 응용해서 실수를 표현해보자. 16비트를 사용한다고 가정하면 앞의 8비트는 정수 부분을, 나머지 8비트는 소수 부분을 위해서 할당하면 될 것이다. 예를 들어 5.34(10)의 경우에는 101.010101110...(2)의 무한 소수 형태의 이진수가 되는데, 앞서 말한 방식으로는 16비트의 다음 숫자가 된다.

00000101 01010111(2)

이런 표기 방법은 앞선 포스팅들에서 다뤘던 정수 표현 방법을 정수 부분과 소수 부분에 각각 적용한 것이다. 이 방법은 고정 소수점 표현(fixed-point representation)이라고 하며, 아주 큰 숫자가 아니거나 소수점 아래가 아주 길어서 정확한 실수 값을 사용하지 않는 경우라면 사용할 수 있다. 즉 소수점의 위치를 고정시켜 표현하는 방식인데 크고 정밀한 실수를 표현하지 못하기 때문에 컴퓨터에서는 사용되지 않는다. 일반적으로 컴퓨터에서는 정수 표현에 초과 표기법(excess notation)을, 소수 표현에 부동 소수점 표기법(floating-point notation)을 사용한다.

<부동 소수점 표기법>

0.34(10)를 컴퓨터에서 사용하기 위해 이를 이진수로 바꾸면 다음처럼 무한 소수가 된다.

0.010101110...(2)

이를 정규형(nomalized form)으로 바꿔보자. 정규형이란 정수 부분에 0이 아닌 수 하나만 남기는 것을 말한다. 정수를 한 자리수만 남김으로써 실수의 표현법을 통일하려는 의도로 사용되는데, 정규형을 사용하지 않으면 10.10*2^(-3)이나 0.1010*2^(-1) 등 하나의 숫자에 대해 너무나 많은 표현이 가능하기 때문이다. 아무튼 위 숫자에 대한 정규형은 아래와 같다.

1.0101110...*2^(-2)

이 숫자에서 지수와 가수를 나누어 아래 형식처럼 표현한다. 8비트를 가정했을 때, 각 부분에 다음처럼 비트를 할당한다고 생각해보자.

Sign(1)

Exponent(3)

Significand(4)

여기서 지수(exponent)를 위해 3비트를 할당했기 때문에 3 초과 표현(excess 3 representation)을 사용한다. 즉, 정규형으로 표현된 1.0101110*2^(-2)를 표현하기 위해서는 지수가 -2이기 때문에 3을 초과시켜서 1을 적는다(-2+3=1).

또한 가수는 1.0101110이기 때문에 10101110이 되는데, 가수부분으로 4비트를 할당했기 때문에 1010이 된다. 따라서 이를 그대로 표현하면 아래와 같다.

부호  지수  가수
0       001  1010

지수 표현을 위한 비트수와 가수 표현을 위한 비트수의 할당에 따라 표현할 수 있는 숫자의 범위와 정확도가 결정된다. 즉, 지수에 더 많은 비트를 할당하면 더 큰 절대값을 가지는 숫자의 표현이 가능해지고, 가수에 더 많은 비트를 할당하면 보다 정확한 수를 표현할 수 있게 된다.

다시말해 0.34(10)이라는 값을 사용하면 8비트 컴퓨터 내부에서는 0001 1010(2)라는 이진수로 저장된다는 것이다. 이를 다시 정규형으로 표현하면 1.010*2^(-2)가 되고, 이 숫자는 십진수 0.3125이다. 원래 표현하려던 숫자와 오차가 발생하는 것이다. 이를 절삭오차(truncation error 또는 round-off error)라고 부르는데, 유효숫자 부분의 자리수가 부족하여 저장될 값의 일부를 잃어버리는 것을 의미한다.

절삭오차와 관련된 문제는 수치해석 분야에서 일하는 사람들에게는 일상적인 관심사항이다. 수치해석에서는 큰 숫자들이나 높은 정밀도를 요하는 계산을 수행할 때 발생하는 문제들을 다룬다.

<초과 표기법>

위에서 잠시 언급했던 초과 표현(excess representation)에 대해 좀 더 알아보자. 3 초과 표현을 예로 들면 이는 표현하고자 하는 수보다 3을 초과시켜 표현하는 것이다. 아래 표와 같다.

숫자

3 초과 표현

2의 보수 표현

-4

100

-3

000

101

-2

001

110

-1

010

111

0

011

000

1

100

001

2

101

010

3

110

011

4

111

초과 표현은 왜 사용하는 것일까? 아래의 두 수는 정규형으로 표현된 수이다. 두 숫자 중 어떤 수가 큰 수인지 어떻게 알 수 있을까?

1.000 * 2^0
1.111 * 2^(-1)

이를 비교하려면 10진수로 변환하여 비교하거나 지수 값을 동일하게 바꾸면 된다. 두 번째 수의 지수를 첫 번째와 동일하게 바꿔보자.

1.000   * 2^0
0.1111 * 2^0

하지만 정규형에서는 이런 과정을 거칠 필요없이(가수를 볼 필요 없이) 지수가 큰 수가 큰 수이다. 왜나하면 정규형에서는 두 수의 부호가 같은 경우는 가수가 아무리 커도 지수가 큰 수가 큰 수이기 때문이다. 지수 값이 차이가 난다면 가수를 볼 필요가 없고, 지수 값이 같다면 가수를 비교해야 한다. 위의 예를 다시 표현해보자.

0 011 1000 (1.000*2^0)
0 010 1111 (1.111*2^(-1))

이처럼 지수와 가수의 상대적인 위치 배치와 지수에 대한 초과 표기법을 사용하기 때문에 실수의 대소 비교 연산을 수행할 때는 따로 실수라고 생각하지 않고 정수의 대소 관계처럼 생각해도 무방하다. 이처럼 지수 영역을 위해서 초과 표현을 사용하면 같은 부호일 경우에는 전체의 비트 패턴을 정수처럼 생각해도 대소 관계를 파악할 수 있게 된다. 실수의 연산보다 정수의 연산이 더 빠르기 때문에 이는 큰 장점이 된다. 대부분의 CPU에는 실수 연산을 위한 전용 프로세서인 FPU(Floating Point Unit)이 있어서 상대적으로 느린 실수 연산을 보완하지만 여전히 정수 연산히 상대적으로 고속이기 때문이다. 이는 초과 표현의 중요한 특징 중 하나이다.

※Hidden bit

hidden bit 아이디어를 이해하기 위해 앞에서 예로 들었던 숫자를 보자.

1.0101110*2^(-2)

2진수 정규형으로 표현된 수의 정수 부분은 항상 1이다. 2진수에서 0이 아닌 숫자는 1뿐이기 때문이다. 그럼 2진수의 정규형으로 표현된 숫자는 정수 부분의 1을 표현하지 않아도 되는 것이 아닐까? 그래서 1을 숨기기로 하자. 여기서 숨긴 비트(1)를 hidden bit라 한다. 따라서 hidden bit 를 사용하면 가수를 1비트 더 표현할 수 있게 된다. 아래의 비교를 보자.

hidden bit 사용 전

0 001 1010

hidden bit 사용 후

0 001 0101

이렇게 하면 원래는 1.010*2^(-2)까지만 표현 가능했던 비트가 1.0101*2^(-2)까지 표현할 수 있게 됨으로써 좀 더 정확한 숫자를 나타낼 수 있게 된다.

※Special value
 
hidden bit를 사용하면 3 초과 표기법 사용 하에서 0 000 000(2)는 1.0000*2^(-3)가 되어 0.125가 된다. 즉, 0이 0이 아니게 되는 것인데, 이를 위해 0 000 0000(2)를 0으로 사용하도록 약속하기로 한다. 이것이 0(10)의 표현을 위한 special value의 개념이다. 따라서 다음처럼 표현 가능 범위가 정해진다.

8비트 부동 소수점 표현

십진수

가장 작은 양의 실수

0 000 0001

0.1328125

가장 작은 음의 실수

1 000 0001

-0.1328125

가장 큰 양의 실수

0 111 1111

31

가장 큰 음의 실수

1 111 1111

-31

이 내용을 정리하면 8비트 부동 소수점 표기법에서는 다음 범위 만을 커버할 수 있다는 결론이 난다.

-31~-0.1328125
0
0.1328125~31

연산 중 이 범위를 넘어가게 되면 overflow나 underflow가 발생하게 된다.

<IEEE 754 Floating Point 표준>

컴퓨터 내부에서 실수를 표현하는 국제 표준을 'IEEE 754'라고 한다. 위에서 설명한 내용은 이에 대한 극히 일부분이며, IEEE 754에서는 단 정밀도(single precision)과 배 정밀도(double precision)에 따라 각각 32비트와 64비트를 사용하며 몇 가지 특징적인 값을 위한 고려사항이 포함되어 있다. 예컨대 0과 같은 special value 말고도 어떤 수를 0으로 나누었을 때 발생하는 무한대 값, 허수 등의 NaN(Not a number), underflow가 최대한 발생하지 않도록 하기 위한 denormalized form 등의 경우를 위한 special value가 여기에 속한다.

Single precision(32비트)

Sign(1)

Exponent(8)

Significand(23)

Sign(1)

Exponent(11)

Significand(52)