컴퓨터는 데이터를 이진수 체계를 이용해 0과 1로 저장합니다.
정수를 저장할 경우 해당 정수를 이진수로 변환한 후 메모리에 저장하는데, 우측부터 2⁰, 2¹, 2²... 순으로 해석하여 변환합니다.
그런데 125.275나 25.23423112342343... 같이 소수부가 포함된 실수는 어떻게 저장할까요?
두 실수 사이에는 무수히 많은 실수가 존재한다는 특성상, 이를 유한한 비트로 나타내려면 정수의 변환과는 다른 복잡한 규칙이 필요합니다.
이를 위해 개발된 대표적인 두 가지 방법인 고정소수점(Fixed-point) 과 부동소수점(Floating-point) 방식을 살펴보겠습니다.
고정소수점 방식 (Fixed-point)
고정소수점 방식은 실수를 이진수로 변환할 때 정수 부분과 소수 부분을 각각 별도의 정수처럼 저장하는 방식입니다.
부동소수점 방식보다 먼저 사용되던 방식으로, 부동소수점이 등장한 이후 두 방식을 구분하기 위해 "고정소수점"이라 부르게 되었습니다.
아래 설명은 널리 사용되는 Q8.8 형식 (정수부 8비트 + 소수부 8비트, 총 16비트) 을 기준으로 합니다.
변환 과정
1단계) 정수부와 소수부를 각각 이진수로 변환
125.625
- 정수부
125→01111101 - 소수부
0.625→10100000
2단계) 두 이진수를 결합하여 16비트로 저장
01111101 10100000
└─정수부─┘└─소수부─┘
장점
- 정확한 표현: 소수 부분을 정수처럼 저장하기 때문에 지정된 크기 내에서는 정확한 값을 유지할 수 있습니다.
- 구현 간단: 정수의 저장 방식과 연산 방식을 그대로 사용하므로 직관적이고 구현하기 쉽습니다.
단점
- 유연성 부족: 정수부와 소수부의 저장 공간 크기를 미리 결정해야 하므로, , 정해진 크기보다 작은 수가 들어온다면 저장공간이 낭비되고, 정해진 크기보다 큰 수가 들어온다면 값이 넘쳐 손실이 일어나는 등 예외적인 값들에 대한 효율적 대응이 어렵기에 초기에 저장 공간의 크기를 잘 설정해야 합니다.
- 하드웨어 미지원: 과거에는 연산 시 정수의 연산 체계를 그대로 사용하기에 빠른 연산 속도가 장점이었지만, 현대 CPU에는 대부분 부동 소수점 연산을 빠르게 처리하는 FPU(Floating Point Unit)가 내장되어 있어 상대적으로 고정 소수점 방식이 느려졌습니다.
부동소수점 방식 (Floating-point)
부동소수점 방식은 실수를 sign(부호비트), exponent(지수부), fraction(가수부) 의 세 가지 구성 요소로 나누어 저장합니다.
아래 설명은 널리 사용되는 IEEE 754 단정밀도(32비트) 표준을 기준으로 합니다.
32비트 구성
| 구성 요소 | 비트 수 | 역할 |
|---|---|---|
| sign (부호비트) | 1비트 | 양수(0) / 음수(1) |
| exponent (지수부) | 8비트 | 소수점 위치 표현 (bias 127 적용) |
| fraction (가수부) | 23비트 | 정규화된 실수 값 저장 |
- 지수부는 0~255 저장 가능하며, 0과 255는 특수값 예약
- 실제 지수 표현 범위: -126 ~ 127 (저장 시 127을 더해 1~254로 저장 → 이 127을 bias라 함)
💡 bias란?
지수부는 8비트 부호 없는 정수(0~255)로 저장됩니다. 그런데 실제 지수 값은 음수도 될 수 있습니다 (예:
0.001을 정규화하면1.0 × 2⁻³). 부호 없는 정수로 음수 지수를 표현하기 위해 실제 지수 값에 127을 더한 값을 저장하는 방식을 사용하는데, 이 더해주는 값 127을 bias 라고 합니다.
실제 지수 저장되는 값 (지수 + 127) -126 1 0 127 6 133 127 254 이렇게 하면 별도의 부호 비트 없이도 지수부만으로 음수 지수를 표현할 수 있고, 저장된 값이 클수록 실제 지수도 크다는 대소 관계가 유지되어 부동소수점 수의 크기 비교도 간단해집니다.
변환 과정 (-125.625 예시)
1단계) 부호 비트 저장
양수일경우 0 을,
음수일경우 1 을 저장합니다.
여기서는 음수이므로 1 을 저장합니다.
1 | ???????? | ???????????????????????
2단계) 이진수 변환
- 정수부
125→1111101 - 소수부
0.625→.101 - 결합:
1111101.101
3단계) 정규화 및 가수부 저장
소수점을 맨 앞 1 다음으로 이동:
1111101.101 → 1.111101101 × 2⁶
이후, 맨 앞 1을 제외한 나머지 111101101를 가수부에 저장합니다.
이 맨 앞의 1은 정규화 과정에서 항상 존재하는 것이 보장되는 값으로(맨 앞 1 다음으로 소수점을 옮기기에) 암묵적으로 간주되므로 저장할 필요가 없습니다(이를 "hidden bit"라고 함).
가수부의 제일 왼쪽부터 111101101을 채우고, 나머지 빈 공간은 0으로 채웁니다.
1 | ???????? | 11110110100000000000000
4단계) 지수부 저장
소수점 이동 자릿수 6 + bias 127 = 133 → 이진수 10000101
1 | 10000101 | 11110110100000000000000
장점
- 넓은 표현 범위: 같은 비트 수로 고정 소수점 방식보다 훨씬 넓은 범위의 숫자를 표현할 수 있습니다. 실수 전체를 이진수로 변환하여 가수부에 저장한 후, 소수점의 위치를 지수부에 저장하기 때문에 소수점의 위치를 유연하게 지정할 수 있습니다.(부동 = 소수점이 둥둥 떠다님) 그렇기에 정수와 소수 각각의 저장에 사용되는 비트를 고정할 필요가 없으므로, 가수부의 공간에 정수가 작을 경우 소수 저장에 더 많은 비트를 사용할 수 있고, 소수가 작을 경우 정수 저장에 더 많은 비트를 사용할 수 있기에 고정소수점 방식에 비해 저장 공간을 효율적으로 사용할 수 있습니다.
- 하드웨어 지원: 현대 CPU에는 부동소수점 연산을 빠르게 처리하는 전용 회로(FPU, Floating Point Unit)가 내장되어 있어 빠른 연산이 가능합니다.
단점
- 정밀도 손실: 일부 실수(예: 0.2, 0.3)는 이진 부동소수점으로 정확히 표현할 수 없어(0.2는 이진수로 0.00110011001100... 같이 무한히 반복되는 형태가 됨) 근삿값으로 저장됩니다.
- 오차 누적: 부동소수점 수를 이용해 반복적인 연산을 하는 과정에서 작은 오차가 누적되면 계산 결과가 부정확해질 확률이 높아집니다.
- 특수값 처리:
NaN,무한대등 특별한 값을 처리하기 위한 추가 로직이 필요합니다.
각 방식의 적합한 사용 사례
| 방식 | 적합한 분야 | 이유 |
|---|---|---|
| 고정소수점 | 금융, 회계, 암호화폐 거래소 | 미세한 오차조차 허용되지 않는 정확한 금액 계산 필요 |
| 부동소수점 | 물리 시뮬레이션, 날씨 예측, 3D 그래픽, 머신러닝 | 넓은 숫자 범위를 빠르게 처리해야 하며, 작은 오차는 허용 가능 |
정리
실수 표현 방식
├── 고정소수점: 정확도 ↑, 표현 범위 ↓, 구현 간단
└── 부동소수점: 표현 범위 ↑, 정확도 ↓ (근삿값), 하드웨어 가속 지원
두 방식 모두 장단점이 명확하기 때문에, 어떤 정밀도와 범위가 필요한지에 따라 적절한 방식을 선택하는 것이 중요합니다.