<aside> ⚠️ **0.1f + 0.2f == 0.3f가 아닌** 이유 정도는 알아야 읽기 수월할지도?

</aside>

IEEE 754란?

IEEE 754는 부동소수점에 대한 표준이다.

저장 방식과 사칙연산, 예외 상황이나 각종 초월함수 등 다양한 작업에 대해 다룬다.

모든 곳에서 반드시 지켜지는 것은 아니다. 지키지 않을 수도 있다.

개요

32비트 단정밀도 float은 부호 1비트/지수부 8비트/가수부 23비트를, 64비트 배정밀도 double은 지수부 11비트/가수부 52비트를 사용한다고 한다.

그래서 혹시 이걸로 왜 1.0f 0x3F800000인지 설명할 수 있는 분?

부동소수점으로 정확히 어떻게 표현되는지 아는 것을 목표로 간단히 알아보자.

부호 비트

부호있는 정수(signed integer)는 맨 앞 1비트를 부호를 나타내는 데 사용한다.

마찬가지로 부동소수점에서도 맨 앞 1비트를 부호를 나타내는 데 사용한다.

하지만 일반적으로 2의 보수를 사용하는 부호 있는 정수와는 달리,

부동소수점은 1의 보수처럼 부호 비트가 1이라면 단순히 -를 붙여준다.

일부 경우에서 0.0f-0.0f가 다르게 취급되는 이유가 이것이다.

int32_t의 경우

32비트 float의 경우

가수부

어떤 수를 과학적 기수법으로 나타내면 1.BBBeXX 또는 -1.BBBeXX 꼴이 된다.

예를 들어 십진수 100.625를 이진수로 나타내면 1100100.101가 되고, 과학적 기수법으로 나타내면 1.100100101e6이 된다. (1.100100101 × 2^6)

가수부가 10비트인 16비트 반정밀도의 경우 가수부가 1001001010이 된다.

지수부 (간단히)

지수부가 5비트인 16비트 반정밀도의 경우 지수가 1이면 지수부가 10000이 된다.

위에서 예로 든 십진수 100.625의 경우, 1.BBBeXXXX 부분에 6이 들어간다.

그러므로 십진수 100.625를 16비트 반정밀도로 표현하면 지수부는 10101이 된다.

그래서 십진수 100.625가 16비트로 0101011001001010, 즉 0x5696이 되는 것이다.

마찬가지로 32비트로는 010000101100100101000000000000000, 즉 0x42C94000

이렇게만 할 경우 문제점

위처럼 간단히 모든 수를 표현할 수 있다면 좋겠지만 해결해야 할 문제가 남았다.

0은 과학적 표기법으로 나타낼 때 1.BBBeXX 꼴이 되지 않아 0을 나타낼 수 없다.

그리고 큰 문제는 아니지만 지수부가 0이 되면 그보다 작은 수를 나타낼 수 없다.

그래서 지수부가 0인 경우 맨 앞이 1.이 아닌 0.으로 봐 두 문제를 모두 해결한다!

또 다른 문제점

... 그리고, NaN, infinity, -infinity

지수부의 모든 비트가 1인 경우는 특별한 수를 위해 예약되어 있다.

가수부가 0이면 infinity로 (부호 1비트가 1이면 -infinity), 아니면 NaN으로 본다.

내용이 달라도 0b0_11111_0101010101NaN이고 0b0_11111_111111111NaN이다.

정리

  1. IEEE 754는 부동소수점에 대한 표준이다.
  2. 부동소수점은 부호 비트와 지수부, 가수부로 이루어진다.
  3. 부호 비트가 0이면 양수, 1이면 음수
  4. $n$비트의 지수부가 $0$, $1$ ~ $2^n-1$인 경우 지수는 $-2^{n-1}+2$, $-2^{n-1}+2$ ~ $2^{n-1}$
    1. 지수부가 0인 경우 과학적 표기법에서 맨 앞 부분이 1.이 아닌 0.으로 시작
  5. 가수부는 과학적 표기법으로 나타낼 때 소수점에 들어가는 부분
  6. 지수부의 모든 비트가 1인데 가수부가 0이면 infinity (부호 비트에 따라 -infinity)
  7. 지수부의 모든 비트가 1인데 가수부가 0이 아니면 NaN

부동소수점이 어떻게 저장되는지, 그리고 왜 그렇게 저장되는지까지 간단히 알아봤다. -끝-