[컴퓨터 구조] 고정 소수점 & 부동 소수점

xoey·2024년 10월 17일

컴퓨터 구조

목록 보기
4/6
post-thumbnail

서문

컴퓨터에서 실수를 표현하는 방법은 정수에 비해 훨씬 복잡하다.

실수는 정수와 달리 소수점 이하의 값을 다루어야 하기 때문에, 이를 2진수(0, 1)로만 표현해야 하는 컴퓨터에서는 다양한 방법들이 연구되어 왔다. 특히 실수 연산에서 발생하는 오차 문제는 컴퓨터 시스템에서 빈번하게 발생하며, 이를 줄이기 위해 고정 소수점부동 소수점 방식이 도입되었다.

이번 글에서는 두 가지 실수 표현 방식을 살펴보고, 각각의 장단점과 실수 연산의 한계에 대해 알아보자.

1. 고정 소수점(Fixed Point)

고정 소수점 방식은 실수를 표현할 때, 정수부와 소수부를 나타내는 비트 수를 미리 고정해두고, 이를 기반으로 실수를 표현하는 방법이다. 이 방식은 단순하지만, 정밀도와 표현 가능한 범위에 한계가 있다.

1.1. 구성

고정 소수점에서 각 비트의 역할은 다음과 같다:

  • 최상위 비트(MST): 부호(sign)를 나타내며, 양수는 0, 음수는 1로 표시된다.
  • 정수부: 소수점 앞의 정수를 표현하는 비트
  • 소수부: 소수점 이하의 실수를 표현하는 비트

정수부와 소수부의 경계는 소수점의 위치에 따라 고정되며, 이진수로 변환된 값을 해당 비트에 그대로 넣으면 된다. 남는 자리는 0으로 채워 정수를 표현한다.

예시: 10진수 7.625를 32비트 고정 소수점으로 표현하기

10진수 7.625107.625_{10}는 2진수로 변환하면 111.1012111.101_2이 된다. 이를 고정 소수점 방식으로 표현하면 정수부에는 111111, 소수부에는 101101을 각각 저장한다.

1.2. 장점

  • 간단한 구현: 부동 소수점에 비해 실수를 표현하는 방법이 단순하다.
  • 빠른 연산 속도: 고정된 비트 수로 연산하므로, 상대적으로 속도가 빠르다.

1.3. 단점

  • 정밀도 문제: 0.1과 같이 나누어 떨어지지 않는 수는 정확하게 표현할 수 없다.
    • e.g. 0.1100.0001100110011001...20.1_{10}→0.0001100110011001..._2
    • 16비트 이하에서는 반올림 처리되기 때문에, 일부 정보가 손실된다.
  • 표현 범위 제한: 표현할 수 있는 숫자의 범위가 매우 작다.

2. 부동 소수점(Floating Point)

부동 소수점은 소수점이 고정되지 않고 “떠다니는” 방식으로, 보다 넓은 범위의 실수를 표현할 수 있는 방식이다. IEEE 754 표준은 가장 널리 사용되는 부동 소수점 표현 방식이다.

2.1. 구성

부동 소수점에서의 각 비트는 다음과 같은 의미를 가진다:

  • 최상위 비트(MST): 부호를 나타내며, 양수는 0, 음수는 1로 표시된다.
  • 지수부(Exponent): 정규화된 수의 지수를 나타내며, 여기에 bias를 더해 저장한다.
  • 가수부(Mantissa): 정규화된 소수 부분의 값을 저장한다.

💡 Bias란?

부동 소수점 표현 방식에서 지수를 저장할 때 사용하는 보정 값이다. 이를 통해 지수가 음수인 경우에도 양수로 변환해 저장할 수 있도록 도와주는 개념이다. Bias는 특히 IEEE 754 부동 소수점 표준에서 사용된다.
예를 들어 IEEE 754 표준에서는 32비트 부동 소수점에서 Bias 값은 127로 사용한다.

예시: 10진수 7.625를 32비트 부동 소수점으로 표현

7.625107.625_{10}를 2진수로 변환한 후, 이를 정규화하면 1.111012×221.11101_2×2^2 형태가 된다. 지수에 127의 bias를 더해 지수부에 저장하고, 가수부에는 소수부를 저장한다.

2.2. 장점

  • 표현 범위 확대: 부동 소수점은 고정 소수점에 비해 더 큰 수와 더 작은 수를 표현할 수 있다.
    • 부동 소수점 지수부에 들어갈 수 있는 가장 큰 숫자는 11111110211111110_2이다.
    • 이를 10진수로 바꾸면 25410254_{10}이다.
    • 정규화 결과로 가질 수 있는 가장 큰 지수는 254127=127254-127=127이다.
    • 즉, 32비트 부동 소수점에서 가질 수 있는 가장 큰 수의 정규화 결과는 1.nnn×21271.nnn×2^{127}이다.

2.3. 단점

  • 정밀도 손실: 여전히 제한된 비트 수 때문에, 정밀도가 떨어질 수 있다. 특히 0.1과 같은 수는 정확하게 표현할 수 없으며, 근사치로 저장된다.

3. 실수 연산에서 발생되는 문제

실수 연산에서 발생하는 오차 문제는 부동 소수점 방식에서 흔하게 나타난다. 예시 코드로 살펴보자:

const f = () => {
  const a = 0.1;
  const b = 0.2;

  if (a + b === 0.3) {
    console.log('Same');
  } else {
    console.log('Different');
  }
};

위 코드의 출력 결과는 ‘Different’이다. 이는 0.10.10.20.2가 이진수로 정확하게 표현할 수 없는 무한 소수이기 때문에 발생한다. 컴퓨터에 저장될 때는 0.10.1에 가장 가까운 값으로 저장되며, 그 결과 두 수의 합이 0.3000000000000000420.30000000000000004_2처럼 약간의 오차를 포 함하게 된다.

3.1. 해결 방법: 정수로 변환

정확한 실수 연산을 위해 정수로 변환한 후 계산하는 방법을 사용할 수 있다. 실수에 10을 곱해 정수로 만든 뒤 연산을 수행하는 방식이다.

const f = () => {
  const a = 0.1;
  const b = 0.2;
  const intA = a * 10;
  const intB = b * 10;
  const intResult = 0.3 * 10;

  if (intA + intB === intResult) {
    console.log('Same');
  } else {
    console.log('Different');
  }
};

10을 곱해도 무한 소수인 건 변함 없는 것 아닌가?

0.1×100.1×101.00000000000000011.0000000000000001과 같은 값이지만, 이 값을 정수로 변환(내부적으로는 소수점을 없애고 정수로 취급)하는 과정에서 오차가 보정되어 정확한 11로 간주될 수 있다.

마치며

컴퓨터가 0과 1만으로 데이터를 표현해야 하다 보니, 인간이 실수를 단순하게 표현하는 것보다 훨씬 복잡한 연구가 필요했을 것 같다. 특히, 우리가 무시할 수 있는 작은 오차라도, 우주선처럼 극도로 정밀한 연산이 필요한 상황에서는 그 오차가 매우 중요한 문제가 되었을 것이다.

실제로 내가 짜는 코드에서도 많은 연산이 이루어졌을 텐데, 지금까지 이런 실수 표현으로 인한 오류를 경험하지 않았다는 게 신기하다. 만약 그런 오류가 발생했더라면, 왜 틀렸는지 고민하며 시간을 보냈을 것이다. 이제 이런 개념을 알게 되었으니, 향후 비슷한 문제가 발생했을 때 떠올릴 수 있는 문제 원인을 하나 알게 되어 유익했다.


Reference

profile
[Roman 8:18] consider that our present sufferings are not worth comparing with the glory that will be revealed in us.

2개의 댓글

comment-user-thumbnail
2024년 10월 17일

👍

1개의 답글