32비트를 그냥 정수 표현에 사용하면 int32는 약 -21억부터 +21억까지의 모든 정수를 정확하게 표현할 수 있습니다. 100000000, 100000001, 100000002처럼 서로 1 차이 나는 값도 모두 구분할 수 있습니다. 대신 약 21억을 넘어가는 큰 수는 표현할 수 없고, 소수도 직접 표현하지 못합니다. 즉 표현 범위는 제한적이지만 그 범위 안에서는 값이 매우 촘촘하고 정확합니다.
반면 32비트 부동소수점인 float32는 32비트를 부호 1비트, 지수 8비트, 가수부 23비트로 나눕니다. 이때 숫자를 1.xxx × 2^n 형태로 표현합니다. 지수 n을 따로 저장하기 때문에 같은 가수부를 가지고도 2^-100을 곱하면 매우 작은 수를, 2^100을 곱하면 매우 큰 수를 표현할 수 있습니다. 그래서 float32는 대략 10^-38 정도의 작은 값부터 10^38 정도의 큰 값까지 다룰 수 있습니다.
하지만 32비트라는 총 공간은 그대로이기 때문에, 지수를 저장하는 데 8비트를 사용한 만큼 숫자의 세밀한 값을 표현하는 데 사용할 수 있는 비트가 줄어듭니다. float32는 실제로 약 24비트 정도의 유효숫자 정밀도만 갖습니다. 그래서 작은 숫자에서는 매우 촘촘한 값을 표현할 수 있지만, 숫자가 커질수록 표현 가능한 숫자 사이의 간격도 커집니다. 예를 들어 1억 근처에서는 100000000과 100000001을 서로 다른 값으로 정확히 표현하지 못할 수 있고, 대략 8 정도 간격으로 표현 가능한 값이 존재합니다.
float32에서 1억 근처의 숫자 간격이 8이 되는 이유는, float32가 숫자의 크기와 상관없이 유효숫자를 약 24비트까지만 유지하기 때문입니다. 1억은 2²⁶ = 67,108,864와 2²⁷ = 134,217,728 사이에 있으므로, 이 구간의 수는 1.xxxxx × 2²⁶ 형태로 표현됩니다. float32의 가수부는 저장 공간이 23비트이고, 정규화 과정에서 생략되는 맨 앞의 1까지 포함하면 실제 유효숫자는 24비트입니다.
이때 가수부의 가장 마지막 비트는 2⁻²³ 위치를 의미합니다. 그런데 전체 숫자에는 2²⁶이 곱해져 있으므로, 이 마지막 비트 하나가 실제 값에 미치는 영향은 2⁻²³ × 2²⁶ = 2³ = 8이 됩니다. 즉 가수부의 마지막 비트가 하나 바뀔 때 실제 숫자는 8씩 변합니다.
그래서 1억 근처에서 float32가 정확히 표현할 수 있는 값은 99,999,984, 99,999,992, 100,000,000, 100,000,008, 100,000,016처럼 8 간격으로 존재합니다. 따라서 100,000,001이나 100,000,002 같은 값은 float32 안에 정확히 대응되는 비트 패턴이 없습니다. 이런 값을 float32로 변환하면 가장 가까운 표현 가능한 값으로 반올림됩니다. 예를 들어 100,000,001은 100,000,000으로 저장되고, 100,000,007은 100,000,008로 저장됩니다.
결국 숫자가 커질수록 지수는 커지지만 가수부의 비트 수는 늘어나지 않기 때문에, 가수부의 마지막 한 비트가 나타내는 실제 값도 커집니다. 그래서 2²³ 근처에서는 간격이 1이고, 2²⁴ 근처에서는 2, 2²⁵ 근처에서는 4, 2²⁶ 근처에서는 8이 됩니다. 이것이 float32에서 숫자가 커질수록 표현 가능한 숫자 사이의 간격이 커진다는 의미입니다.
따라서 지수를 사용하지 않는 방식은 좁은 범위를 대신 정확하고 촘촘하게 표현하는 방식이고, 지수를 사용하는 부동소수점 방식은 정밀도를 일부 포기하는 대신 아주 작은 수부터 아주 큰 수까지 넓은 범위를 표현하는 방식입니다. 결국 float32에서 지수 8비트를 따로 둔 것은 제한된 32비트 안에서 표현 범위를 크게 확장하기 위한 선택이며, 그 대가가 정밀도 손실입니다.
참고로 부동소수점(Floating Point)이라는 이름은 소수점의 위치가 고정되어 있지 않고 지수에 따라 움직이기 때문입니다.
예를 들어 이진수 1101.01₂를 정규화하면 1.10101₂ × 2³이 됩니다. 여기서 가수부 1.10101은 유지하면서 지수를 바꾸면 숫자의 크기가 달라집니다. 1.10101 × 2⁰, 1.10101 × 2³, 1.10101 × 2⁶처럼 지수가 달라질 때마다 실제 숫자에서 소수점이 위치하는 곳도 달라지는 셈입니다.
반대로 고정소수점(Fixed Point)은 소수점 위치를 미리 정해 놓습니다. 예를 들어 32비트 중 16비트는 정수부, 16비트는 소수부라고 정하면 소수점은 항상 같은 위치에 있습니다.
그래서 이름을 비교하면 직관적입니다. 고정소수점은 소수점 위치가 fixed, 즉 고정되어 있고, 부동소수점은 지수에 따라 소수점 위치가 floating, 즉 떠다니듯 이동합니다.
엄밀히 말하면 실제 메모리 안에 소수점 기호 .를 저장하는 것은 아닙니다. 가수와 지수를 저장하고, 지수에 따라 소수점의 위치가 달라지는 효과를 내기 때문에 부동소수점이라고 부르는 것입니다.
'개발' 카테고리의 다른 글
| ‘Discord로 로그인’을 누르면 무슨 일이 일어날까? (0) | 2026.09.06 |
|---|---|
| LLDB을 이용한 C++ 디버깅 원리 (1) | 2026.08.30 |
| vscode에서 파이썬 프로그램을 디버깅 하는 방법 (0) | 2026.08.16 |
| 터미널에서 ctrl+c를 눌렀을 때 어떻게 동작할까? (0) | 2026.08.09 |
| docker 컨테이너의 프로세스 구조 간단히 알아보기 (1) | 2026.08.02 |