C++/C++ 문법과 핵심 개념

[C++ 실수 자료형 2] float와 double의 내부 구조

loooong 2026. 8. 6. 03:23

C++ float와 double의 내부 구조

C++의 float와 double은 일반적으로 IEEE 754 부동소수점 형식을 사용한다.

 

부동소수점은 실수를 다음 세 부분으로 나누어 저장하는 방식이다.

부호 × 유효숫자 × 2의 지수

 

10진수의 과학적 표기법과 비슷하다.

12345 = 1.2345 × 10⁴
0.00123 = 1.23 × 10⁻³

 

컴퓨터에서는 10의 거듭제곱 대신 2의 거듭제곱을 사용한다.

1.10101₂ × 2³

지수에 따라 소수점 위치가 이동하므로 소수점이 고정되어 있지 않다는 의미에서 부동소수점이라고 부른다.

 

이진수 정규화

10진수 13.25를 이진수로 변환하면 다음과 같다.

13.25₁₀ = 1101.01₂

이를 정규화하면 다음과 같다.

1.10101₂ × 2³

소수점을 이동하여 맨 앞에 1만 남기는 형태이다.

정규화된 이진수는 일반적으로 다음 형태를 가진다.

1.xxxxx₂ × 2ⁿ

여기서 부호, 지수, 유효숫자를 각각 저장한다.

 

float의 구조

일반적인 float는 32비트로 구성된다.

[부호 1비트] [지수 8비트] [가수부 23비트]

 

각 영역의 역할은 다음과 같다.

  비트 수 역할
부호 1 양수와 음수를 구분한다.
지수 8 숫자의 크기와 소수점 위치를 표현한다.
가수부 23 숫자의 세부적인 유효 정보를 표현한다.

 

개념적인 값 계산식은 다음과 같다.

값 = (-1)부호 × 1.가수부 × 2지수

실제 IEEE 754에서는 지수에 바이어스를 적용하고, 특수 값과 서브노멀 값을 별도로 처리한다.

 

double의 구조

일반적인 double은 64비트로 구성된다.

[부호 1비트] [지수 11비트] [가수부 52비트]

 

  전체 비트 부호 지수 가수부
float 32 1 8 23
double 64 1 11 52

double은 float보다 지수와 가수부에 더 많은 비트를 사용한다. 따라서 더 넓은 범위와 높은 정밀도를 제공한다.

 

Hidden Bit

정규화된 이진수는 맨 앞자리가 항상 1이다.

1.10101₂
1.00011₂
1.11100₂

맨 앞의 1은 항상 존재하므로 실제 비트에 저장하지 않아도 복원할 수 있다.

실제 유효숫자: 1.10101
저장되는 부분:   10101
생략되는 부분: 1.

 

생략된 선두 1을 다음과 같이 부른다.

  • Hidden Bit
  • Implicit Leading One
  • 암묵적 선두 1

따라서 float의 가수부 필드는 23비트이지만 실제 유효 정밀도는 24비트이다.

저장 가수부 23비트
+ 암묵적 선두 1비트
= 유효 정밀도 24비트

 

double 역시 저장 가수부는 52비트이지만 실제 유효 정밀도는 53비트이다.

 

이진 정밀도와 십진 유효 자릿수

float의 실제 유효 정밀도는 24비트이다.

2²⁴ = 16,777,216

이를 십진 자릿수로 환산하면 다음과 같다.

log₁₀(2²⁴)
≈ 7.22

따라서 float는 약 6~7자리 정도의 십진 유효숫자 정보에 해당하는 정밀도를 가진다.

 

double은 53비트 정밀도를 가진다.

log₁₀(2⁵³)
≈ 15.95

 

일반적으로 다음과 같이 설명한다.

  실제 이진 정밀도 십진 유효 자릿수
float 24비트 약 6~7자리
double 53비트 약 15~16자리

 

유효 자릿수의 의미

유효 자릿수는 소수점 이하의 자릿수가 아니다. 숫자 전체에서 의미 있게 유지되는 숫자의 개수를 뜻한다.

1234567
123.4567
0.001234567

위 값들은 모두 약 7개의 유효 숫자를 가진다.

 

따라서 값의 크기가 커지면 작은 변화량을 표현하기 어려워진다.

float value = 100000000.0f;
value += 1.0f;

100000000 부근에서는 인접한 float 값 사이의 간격이 1보다 크다. 따라서 1.0f를 더해도 저장된 값이 변하지 않을 수 있다.

 

digits10과 max_digits10

C++에서는 자료형의 정밀도 정보를 std::numeric_limits로 확인할 수 있다.

#include <iostream>
#include <limits>

int main()
{
    std::cout
        << std::numeric_limits<float>::digits10
        << '\n';

    std::cout
        << std::numeric_limits<float>::max_digits10
        << '\n';
}

일반적인 float에서는 다음 값을 가진다.

digits10 = 6
max_digits10 = 9

digits10은 10진수 값을 부동소수점으로 변환한 뒤 다시 10진수로 변환했을 때 안정적으로 유지되는 최소 자릿수를 의미한다.

max_digits10은 부동소수점 값을 문자열로 출력했다가 다시 읽을 때 원래 값을 복원하기 위해 필요한 최대 자릿수를 의미한다.

두 값은 서로 다른 목적을 가진다.

 

핵심 정리

  • 부동소수점은 부호, 지수, 가수부로 실수를 표현한다.
  • float는 32비트, double은 64비트를 사용한다.
  • float의 가수부 필드는 23비트이지만 Hidden Bit을 포함하면 실제 정밀도는 24비트이다.
  • double의 실제 유효 정밀도는 53비트이다.
  • float는 약 6~7자리, double은 약 15~16자리의 십진 유효 자릿수를 제공한다.
  • 유효 자릿수는 소수점 이하가 아니라 숫자 전체의 정밀도를 의미한다.