실수 표현

1 minute read


컴퓨터의 실수 표현

컴퓨터가 실수를 표현할 때 정수와 마찬가지로 2진법을 사용하기 때문에 정수에 비해 복잡하다.

부동소수점 표현 방식 때문에 다음과 같은 결과가 발생한다.

#include <stdio.h>

int main()
{
  float sum = 0.0f;
  
  for (int i = 0; i < 1000; i++)
  {
    sum += 0.001f;
  }
  printf("sum : %f\n", sum);

  return 0;
}


실행 결과

floating_point_result

0.001을 1000번 더하는 반복문이다. 1이 나와야할 계산이지만 0.999991이라는 근사값이 나오는데 이것이 부동소수점 오차 때문이다.

1. 이진법(binary)

  • 소수를 2진법으로 변환시키는 방법
    소수점 앞 부분(정수부)는 정수를 변환하는 방식 그대로한다.
    소수점 뒤(소수부)부터는 정수부에서 0과 1을 뽑아내는 방식을 반대로 적용시키면 된다.

    2를 곱해주면서 나머지가 0이 될 때 까지 0과 1을 뽑아낸다.
    예) 0.25
    0.25에 2를 곱하고 정수부 0을 뺀 나머지 => 0.5
    0.5에 2를 곱하고 정수부 1을 뺀 나머지 => 0
    소수부 자리에 위 계산에서 나온 정수부 값을 넣어준다.
    그럼 0.01이 2진법으로 표기한 십진수 0.25이다.

  • 계산과정에서 알 수 있듯이 십진수가 2로 떨어지는 수 일 때 변환이 깔끔하게 떨어지지만 아닐 경우 과정이 엄청 길어지거나 무한히 나올 수 있다.


2. 고정소수점(fixed point)

  • 실수를 정수부와 소수부로 나눈다.
  • 소수점을 고정시키고 10진법을 2진법으로 변환시킨 숫자를 그대로 옮기는 방식이다.

    예) 6.25라는 실수가 있다. 이 숫자를 2진법으로 변환하면 110.01이고 32bit 체계에서 다음과 같이 저장된다.

banary_scale_data_type

  • 맨 앞 자리는 부호 비트이며 0이면 양수, 1이면 음수를 나타낸다.
  • 나머지 비트들은 소수점을 기준으로 정수부와 소수부를 표현하는 비트로 나누어지고 이 때 소수점의 위치는 정해진다.
  • 소수부의 경우 앞에서 부터 채우며 남은 자리는 모두 0으로 채워진다.

  • 이러한 방법으로 표현되는 고정소수점 방식은 구현하기 편리하지만 사용하는 비트 수에 비해 표현 가능한 수의 범위와 정밀도가 떨어지기 때문에 범용적인 시스템에서는 거의 쓰이지 않는다.


3. 부동소수점(floating point)

  • 부동(不動)이 아닌 부동(浮動)으로 소수점이 고정되어 있지 않고 움직인다는 뜻이다.
  • 유효숫자의 과학적 표기법과 비슷한 정규화 과정을 거친다.
    • 2진법으로 변환시킨 수의 정수부에 1만 남을 때 까지 소수점을 이동시킨다.
    • 이동한 칸 수를 e라고 하면 1.xx * 2^e의 꼴로 표현한다.
    • 예) 110.01은 1.1001 * 2^2로 표현된다.
  • IEEE 754
    컴퓨터에서 가장 많이 사용되는 부동소수점 표현 방식이다. 실수를 저장할 때 32비트(Single-Precision) 또는 64비트(Double-Precision)가 사용된다.


    비트구조는 다음과 같다. (32비트 기준) banary_scale_data_type_2

  • 고정소수점과 마찬가지로 부호비트를 가진다.
    가수부에는 정규화 결과 소수점 오른쪽에 있는 숫자들이 왼쪽부터 채워지며 남는 자리는 0으로 채워진다.
    지수부에는 2^e의 e에 해당하는 수를 2진수로 바꾼 수가 들어온다.
  • 이 때 지수가 음수인 경우를 처리하기 위해서 바이어스 표현법을 사용한다.
  • 지수에 바이어스 상수(= 127)를 더한 값을 2진수로 변환한 뒤 지수부에 들어간다.


  • 예) 6.25를 부동소수점으로 표현하면
    이진수 변환 => 110.01
    정규화 => 1.1001 * 2^2
    바이어스 표현법 => 1.1001 * 2^(2 + 127)


    비트에 다음과 같이 담긴다.

    result
    부호 양수 0, 지수부 = 10000001, 가수부 1001