신입 게임 개발자의 프로그래밍 일기
[C++ 입문자에서 벗어나기]Chapter_1: 타입(Type)#2 본문
[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을 써야 한다.
'Language > C++' 카테고리의 다른 글
[C++ 입문자에서 벗어나기]Chapter_2: 선언과 정의#2 (0) | 2017.11.08 |
---|---|
[C++ 입문자에서 벗어나기]Chapter_2: 선언과 정의#1 (0) | 2017.11.05 |
[C++ 입문자에서 벗어나기]Chapter_1: 타입(Type)#3 (3) | 2017.11.03 |
[C++ 입문자에서 벗어나기]Chapter_1: 타입(Type)#1 (0) | 2017.10.17 |
[C++ 입문자에서 벗어나기]Chapter_0: 목표(갱신: 2017년 10월 17일 목요일) (0) | 2017.10.17 |