목차
- 01. Intro
- 02. 부동소수점
- 특징 및 구조
- 부동소수점 변환 과정
- 한계점
- 해결 방안
- 특수값
- 03. 마무리
- 04. 연관 내용
01. Intro
오늘은 float형과 double형에서 사용하는 [부동소수점]에 대해서 알아보겠습니다.
02. 부동소수점
특징 및 구조
부동소수점(Floating Point)은 소수를 표현하는 방식 중 하나입니다.
소수점 위치를 유동적으로 조정할 수 있도록 설계된 숫자 표현 방식입니다.
그래서, 고정된 자리수로 표현하는 정수형과는 다르게 작동합니다.
컴퓨터에서는 IEEE 754 표준에 따라 부동소수점을 이진수로 표현합니다.
여담으로, IEEE 754는 미국 전기전자학회(IEEE)가 1985년에 제정한 국제 표준으로, 컴퓨터에서 부동소수점 숫자를 저장하고 연산하는 방식입니다.
부동소수점은 3개의 부분으로 구성됩니다.
아래는 float형 즉, 32비트(단정도)에서의 부동소수점 구조입니다.
1. S(Sign) : 부호[1비트] → 음수와 양수를 구분합니다. ( 0 → 양수, 1 → 음수 )
2. E(Exponent) : 지수[8비트] → 소수점 위치를 조정하는 값을 가집니다.
3. M(Mantissa) : 가수[23비트] → 실제 숫자를 저장하는 부분입니다.
추가로, double형 즉, 64비트(배정도)에서의 부동소수점 구조는 아래와 같습니다.
1. S(Sign) : 부호[1비트]
2. E(Exponent) : 지수[11비트]
3. M(Mantissa) : 가수[52비트]
부동소수점 변환 과정
10진수 9.625에 대해 IEEE 754 단정도(32비트)로 변환을 해보겠습니다.
먼저, 변환을 위해서는 3가지 과정을 거쳐야 합니다.
1. 10진수를 2진수로 변환합니다.
2. 정규화를 통해 [1.xx * 2^n] 형태로 변환합니다.
3. IEEE 754 형식으로 변환합니다.
위 과정들을 하나씩 수행하며, 값을 변환 하겠습니다.
1. 10진수 → 2진수
먼저, 정수 부분 9을 2진수로 변경하면, 1001(2)입니다.
소수 부분인 0.625를 2진수로 변경하면, 0.101(2)입니다.
참고로, 소수 부분의 2진수는 계속 2를 곱한 뒤, 정수 부분이 1 이상일 때, 1을 빼면 됩니다.
이를 0이 될 때까지 반복하면 됩니다.
그래서, 0.625로 위 과정을 진행하면, 아래와 같습니다.
0.625 x 2 = 1.25 → 1
1.25에서 -1을 한 뒤, 진행합니다.
0.25 x 2 = 0.5 → 0
0.5 x 2 = 1.0 → 1
-1을 진행하면, 0.0이므로 더 이상 진행하지 않습니다.
그래서, 순서대로 값을 가져오면, 0.101(2)가 됩니다.
이를 최종 2진수로 표현하면, 1001.101(2)가 됩니다.
2. 정규화
정규화는 2진수의 숫자를 [1.xxx * 2^n] 형태로 변환합니다.
1001.101(2)를 위 형태로 변환하면, 소수점을 앞으로 3번 옮기면 됩니다.
그래서, n은 3이 되고, 앞 부분은 1.00101(2)가 됩니다.
따라서, 1.00101(2) x 2^3 의 형태로 됩니다.
3. IEEE 754 형식으로 변환
정규화를 거친 값을 부호, 지수, 가수로 변환합니다.
1) 부호
9.625는 양수이므로 부호값은 0을 갖습니다.
2) 지수
정규화할 때, n의 값에 Bias인 127을 더합니다.
따라서, 127 + 3 = 130이 됩니다.
이를 8비트인 2진수로 변환하면, 10000010(2)가 됩니다.
Bias를 더하는 이유는 컴퓨터에 항상 양수의 값을 저장하기 위함입니다.
정규화할 때, n의 값이 음수가 될 수 있습니다.
(예를 들어서, 0.125를 2진수로 변환하면, 0.001(2)가 되고, 이를 정규화하면, 1.000 x 2^(-3)가 됩니다.)
n의 값을 모두 양수로 만들기 위해서는, 8비트의 범위 최솟값인 127을 더하면 됩니다.
추가로, 배정도(64비트)의 지수는 11비트로 11비트의 최솟값인 1023이 Bias로 가집니다.
추후, 지수에 저장된 값을 가져오기 위해서는 Bias만큼 빼서 사용하면 됩니다.
3) 가수
가수는 정규화된 부분의 소수점 부분을 앞에서부터 저장하면 됩니다.
1.001101(2)에서 소수점 부분은 001101 입니다.
이 부분을 앞에서부터 저장해 가수는 00110100000000000000000가 됩니다.
4. 최종 표현
부호, 지수, 가수를 모두 붙이면, 9.625 아래와 같이 표현됩니다.
[부호] [지수] [가수] 순서
1 10000010 00110100000000000000000
실제로, 컴퓨터에 저장될 때, 띄어쓰기는 생략됩니다.
한계점
부동소수점 연산은 정확하지 않는 문제점이 있습니다.
2진수로 변환할 때, 소수점 아래 부분을 완벽하게 표현하지 못하는 경우, 오차가 발생하기 때문입니다.
예를 들어서, 10진수 0.1을 2진수로 변환해 보겠습니다.
0.1 x 2 = 0.2 → 0
0.2 x 2 = 0.4 → 0
0.4 x 2 = 0.8 → 0
0.8 x 2 = 1.6 → 1
0.6 x 2 = 1.2 → 1
0.2 x 2 = 0.4 → 0
... 반복
위 과정을 보면, 0.1을 2진수로 정확하게 표현하지 못합니다.
그래서, 반올림을 진행하므로 반올림 오차가 발생합니다.
해결 방안
1. 부동소수점 오차를 고려해서 사용
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
float a = 0.1f;
float b = 0.1f;
if(fabs(a - b) < 1e-6)
{
//TODO
}
return 0;
}
위 조건문처럼, 오차를 고려해서 같음을 표현하기도 합니다.
2. float형 대신 double형 사용
float형은 단정도로 32비트를 저장할 수 있습니다.
double형은 배정도로 64비트를 저장할 수 있습니다.
double형이 비트를 더 많이 저장하므로, float형보다 오차를 줄일 수 있습니다.
특수값
IEEE 754 표준에는 특정한 비트 패턴을 사용해 특별한 값을 표현할 수 있습니다.
1) +0
부호 : 0
지수 : 00000000
가수 : 00000000000000000000000
2) -0
부호 : 1
지수 : 00000000
가수 : 00000000000000000000000
3) +∞ ( +Infinity )
부호 : 0
지수 : 11111111
가수 : 00000000000000000000000
4) -∞ ( -Infinity )
부호 : 1
지수 : 11111111
가수 : 00000000000000000000000
5) NaN ( Not a Number )
부호 : 0 / 1
지수 : 11111111
가수 : != 0
03. 마무리
오늘은 부동소수점에 대해 자세히 알아봤습니다.
다음에는 다른 주제에 대해서 작성하겠습니다.
04. 연관 내용
읽어주셔서 감사합니다.
틀린 내용 지적은 언제나 환영입니다!
'게임 개발 > C++' 카테고리의 다른 글
| [C++] explicit 키워드 (0) | 2025.03.17 |
|---|---|
| [C++] static 키워드 (1) | 2025.03.16 |
| [C++] 전방 선언 (2) | 2025.03.13 |
| [C++] 접근 지정자 (0) | 2025.03.12 |
| [C++] 포인터 vs 참조 (0) | 2025.03.11 |