신입 게임 개발자의 프로그래밍 일기

[C++ 입문자에서 벗어나기]Chapter_1: 타입(Type)#2 본문

Language/C++

[C++ 입문자에서 벗어나기]Chapter_1: 타입(Type)#2

KFGD 2017. 11. 3. 11:13

[C++ 입문자에서 벗어나기]Chapter_1: 타입(Type)#2


이번 포스팅이에서는 실수를 나타내는 방식인 부동소수점에 대해서 이야기해 볼 것입니다.


[부동소수점]


C++에는 실수를 표현하기 위해 float과 double이라는 타입들이 있습니다.

이들 타입들이 각각 사용하는 "비트의 개수"는 다르지만 IEEE 754 "부동소수점" 방식으로 실수를

표현한다는 것은 동일합니다.

IEEE 754 는 전기 전자 기술자 협회(IEEE)에서 개발한 컴퓨터에서 부동소수점을 표현하는 표준안입니다.

이 부동소수점 표현 방식을 통해 컴퓨터는 "아주 작은 수""아주 큰 수"를 표현할 수 있게 되었습니다.

우리는 이전 포스팅에서 "디지털화"에 대해 다뤄보았습니다.

현실 세계의 정보를 컴퓨터가 이해할 수 있는 비트 집합으로 나타내는 과정인데요.

비트로 표현할 수 있는 숫자들은 2진수로 표현이 가능합니다.


[2진수]


2진수에 대해 곧바로 이야기하기에 앞서 먼저 십진수에 대해 간단히 이야기해봅시다 

일상생활에서 우리들은 주로 십진수로 숫자들을 표현하며 십진수는 아래와 같이 표현됩니다.

각 자리수는 0~9까지의 숫자를 표현할 수 있으면 각 자리수는 10의 제곱만큼 커지거나 작아집니다.



위 십진수를 각 자리수가 이전 자리수보다 10의 제곱만큼 커지는 십진수의 특징을 고려해서 수식으로 표현해봅시다.



이와 유사하게 각 자리수가 이전 자리수보다 2의 제곱만큼 커지는 이진수는 아래와 같이 표현이 될 수 있습니다.



위 수식에서 는 자리수를 표현하며 는 해당 자리에 표현될 숫자를 표현함을 쉽게 알 수 있을 것입니다.



[부동소수점을 표현하는 비트]

이제 본격적으로 부동소수점에 대해 이야기해보겠습니다.

컴퓨터에서 부동소수점은 당연히도 비트 집합으로 표현되는데
이 집합을 구성하는 비트들은 세개의 필드들로 나뉘어집니다.


부호부, 지수부, 가수부


부호부(sign): 실수의 부호를 나타내는 필드

지수부(exponent): 실수의 자릿값을 표현하는 필드

가수부(fraction): 정규화된 실수의 유효숫자들을 표현하는 필드


 

(출처: 위키백과 - 부동소수점)

위 사진은 32비트로 구성된 float 타입에서 사용되는 비트 집합입니다.


이 비트 집합을 이용하여 부동소수점을 처리하는데 컴퓨터가 기본적으로 사용하는 공식은 아래와 같습니다.




는 각각 부호, 지수부, 가수부를 뜻하는데

컴퓨터가 그대로 이 공식에 비트들을 대입하여 사용하는 것이 아닌 지수부의 비트 패턴을 

기준으로 세가지 경우로 나누어서 비트들을 활용하여 부동소수점을 표현합니다.


(콘솔 환경 : 우분투-64비트)


Case 1: 정규화 값(Normalized Value)


첫번째 경우는 "지수부의 비트 패턴이 전부 0 또는 1이 아닌 경우" 입니다.


부호부는 표현할 실수의 부호를 나타내는 값으로 0일 때 양수를 1일때는 음수임을 표현합니다.



지수부 비트들은 아래의 수식을 활용하여 가공되어 표현됩니다.



는 표현할 실수의 자릿값을 표현하는 2진수 값입니다.

는 지수부의 비트들을 2진수로 바꾼 값입니다.

는 지수부 비트 개수에 유동적으로 바뀌는 값으로 

수식으로 결정되는 값으로 는 지수부 비트의 개수를 가리키는 미지수입니다.


결국 원하는 실수 를 표현하는 비트 패턴()를 만들기 위해서는 

에 값을 더하는 아래와 같은 수식을 거치는 것으로 바꾸어 이야기 할 수 있겠습니다..




마지막 가수부는 아래의 수식을 활용하여 가공되어 표현됩니다.



은 정규화 과정을 거친 실수의 유효숫자들을 표현하는 2진수 값입니다.

는 가수부의 비트들을 2진수로 바꾼 값입니다.

"암시적 선두(선행) 1"이라고 이야기하는데 정규화를 거친은 으로 표현되기 때문에

무조건적으로 있는 을 가수부 비트에는 포함시키지 않음으로 추가적으로 무료 비트 한 개를 얻는 기법입니다.


최종적으로 정규화를 거친 2진수 실수 을 표현하는 비트 패턴()를 만들기 위해서는

에 을 빼서 소수점 아래에 위치한 유효숫자들만을 가수부 비트 필드에 맵핑하는 것입니다.

 



콘솔:




Case 2: 비정규화 값(Denormalized Values)


두번째 경우는 "지수부의 비트 패턴이 모두 0인 경우"입니다.

이 경우는 "0을 표현하기""0.0에 매우 가까운 값 표현하기"를 위해 사용됩니다.

정밀도를 포기하는 대신 부동소수점의 범위 확장에 그 목적이 있습니다.



부호는 첫번째 경우와 마찬가지로 표현할 실수의 나타내는 값으로 0일 경우 양수를 1일 경우 음수를 표현합니다.


지수부의 경우는 아래의 수식을 활용하여 표현됩니다.



와 모두 첫번째 경우에서 설명한 것과 동일한 미지수입니다.


가수부의 경우는 아래와 같습니다.



콘솔:


 


 



※주의!

보통 이야기하는 float의 범위는 Case 1: 정규화값(Normalized Values)에서 표현되는 값들을 말합니다.

Case 2: 비정규화값과 이후에 말하는 Case 3: 특수값(Special Values)는 포함되지 않습니다.



Case 2: 특수값(Special Values)


세번째 경우는 "지수부의 비트 패턴이 모두 1인 경우"입니다.

이 경우는"Infinity와 Nan과 같은 특수값들을 표현하기"위해 사용됩니다.

간단하게 가수부가 모두 0이면 Infinity, 아니면 Nan입니다.


콘솔:



 




[부동소수점의 표현 한계]


부동소수점의 Case 1 정규화값(Normalized Values)이라고 무조건적으로 정밀한 것은 아닙니다.

이미 비트 표현 방식에서 간파하신 분들도 있으시겠지만 실수값의 자릿값을 표현하는 지수부 비트가 8개라는 

한계를 가지고 있습니다.

이 한계가 뜻하는 바는 아래와 같습니다.


-가수부의 비트 패턴에 상관없이 지수부가 23이상일 경우, 더이상 소수점 이하 부분을 표시할 수 가 없습니다.


 


8388608이상의 숫자는 소수점 이하를 표시할 수 없으며

지수부가 24일 때는 2의 배수만을 지수부가 25일 때는 4의 배수만을 표시할 수 있습니다.


콘솔:


지수부가 23일 때,


 



 



지수부가 24일 때,


 


 



[부동소수점에 대한 고찰(Fundamental C++ 프로그래밍 p.46 지문 중 발췌)]


부동소수점은 아주 작은 수와 아주 큰 수, 그리고 무한과 NaN을 표현하기 위하여 도입된 타입이다.

표현의 한계로 인하여 오차는 값이 커질수록 기하급수적으로 증가한다.

이 사실을 기억하면서 정수 계산은 정수타입에게 맡기고, 정밀 계산을 위해서라면 계산 전용 라이브러리를 이용해야만 한다. 부동소수점을 사용해야만 한다면 정밀도가 높을수록 좋기 대문에 double을 써야 한다.

Comments