<aside>
⚠️ 0.1f + 0.2f == 0.3f
가 아닌 이유 정도는 알아야 읽기 수월할지도?
</aside>
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
의 경우
0
-2147483648
32비트 float
의 경우
0.0f
-0.0f
어떤 수를 과학적 기수법으로 나타내면 1.BBBeXX
또는 -1.BBBeXX
꼴이 된다.
1.
부분은 공통이므로 생략 (0
과 NaN
등의 예외는 후술)XX
부분이 지수부에, BBB
부분이 가수부에 들어가게 된다.예를 들어 십진수 100.625
를 이진수로 나타내면 1100100.101
가 되고,
과학적 기수법으로 나타내면 1.100100101e6
이 된다. (1.100100101 × 2^6
)
가수부가 10비트인 16비트 반정밀도의 경우 가수부가 1001001010
이 된다.
지수부가 5비트인 16비트 반정밀도의 경우 지수가 1이면 지수부가 10000
이 된다.
float
의 경우 10000000
이 된다.위에서 예로 든 십진수 100.625
의 경우, 1.BBBeXX
의 XX
부분에 6
이 들어간다.
그러므로 십진수 100.625
를 16비트 반정밀도로 표현하면 지수부는 10101
이 된다.
그래서 십진수 100.625
가 16비트로 0101011001001010
, 즉 0x5696
이 되는 것이다.
0
- 1비트10101
- 5비트1001001010
- 10비트마찬가지로 32비트로는 010000101100100101000000000000000
, 즉 0x42C94000
위처럼 간단히 모든 수를 표현할 수 있다면 좋겠지만 해결해야 할 문제가 남았다.
0은 과학적 표기법으로 나타낼 때 1.BBBeXX
꼴이 되지 않아 0을 나타낼 수 없다.
그리고 큰 문제는 아니지만 지수부가 0이 되면 그보다 작은 수를 나타낼 수 없다.
그래서 지수부가 0인 경우 맨 앞이 1.
이 아닌 0.
으로 봐 두 문제를 모두 해결한다!
NaN
, infinity
, -infinity
지수부의 모든 비트가 1인 경우는 특별한 수를 위해 예약되어 있다.
가수부가 0이면 infinity
로 (부호 1비트가 1이면 -infinity
), 아니면 NaN
으로 본다.
내용이 달라도 0b0_11111_0101010101
도 NaN
이고 0b0_11111_111111111
도 NaN
이다.
1.
이 아닌 0.
으로 시작infinity
(부호 비트에 따라 -infinity
)NaN
부동소수점이 어떻게 저장되는지, 그리고 왜 그렇게 저장되는지까지 간단히 알아봤다. -끝-