6. IEEE 부동소수점에서 유효숫자 추출
이 문제에 대해선 아예 설명을 추가해달라고 했던데, 설명해줘도 못 알아먹는다는 데 한 표.
그리고, 이 문제는 사실 검증이 좀 어렵다. Visual Studio에서는 IEEE 16비트 부동 소수점은 아예 구현이 되어있지 않기 때문이다.
IEEE에서는 부동소수점을 \(1.nn \cdot 2^m\) 형태로 표현한 뒤 유효숫자(mantissa)에서 1을 뺀 부분을 저장한다.
이 유효숫자를 추출하는 것이 문제의 요구사항이다.
그런데, 문제에는 함정이 하나 있다. 리턴값은 unsigned int형이며, 최대값이 \(2^{23}-1\), \(2^{10}-1\) 이라는 점이다.
즉, 유효숫자 부분을 추출한 뒤 값의 변화 없이 unsigned int로 강제 형변환을 해서 읽은 결과를 물어보는 문제이다.
대략 아래와 같이 짜면 된다.
#include <stdio.h>
#include <stdlib.h>
unsigned int GetMantissa32inRAW(float value)
{
unsigned int ret = *(unsigned int *)(&value);
return (ret & 0x007fffff);
}
float Conv2Float32inRAW(unsigned int value)
{
value &= 0x007fffff;
value |= 0x3f800000;
return *(float *)(&value);
}
float GetMantissa(float value)
{
if (value < 0) value = -value;
if (value == 0.0) return 0.0;
while (value >= 2.0) value /= 2;
while (value < 1.0) value *= 2;
return value;
}
unsigned int ConvMantissa2UINT(float mantissa, int digit)
{
if (mantissa < 1.0) return 0;
mantissa -= 1.0;
unsigned int ret = 0;
for (int i = 0; i < digit; i++) {
ret <<= 1;
mantissa *= 2;
if (mantissa >= 1.0) {
ret |= 1;
mantissa -= 1.0;
}
}
return ret;
}
unsigned int GetMantissa32(float value)
{
float mantissa = GetMantissa(value);
// value = 1.xxxxx
// 32비트 부동소수점에서는 Mantissa가 23비트로 표현됨
return ConvMantissa2UINT(mantissa, 23);
}
unsigned int GetMantissa16(float value)
{
float mantissa = GetMantissa(value);
// value = 1.xxxxx
// 16비트 부동소수점에서는 Mantissa가 10비트로 표현됨
return ConvMantissa2UINT(mantissa, 10);
}
int main(int argc, char* argv[])
{
const float nValue = 3.14194989f;
unsigned int nMantissaInUINT = GetMantissa32inRAW(nValue);
float nMantissa = Conv2Float32inRAW(nMantissaInUINT);
printf("-= result in raw perspective =-\n");
printf("Mantissa32 in UINT = %u\nMantissa32 in float = %f\n\n", nMantissaInUINT, nMantissa);
printf("-= result in my functions =-\n");
printf("mantissa of %f = %f\n", nValue, GetMantissa(nValue));
printf("GetMantissa32(%f) = %u\n", nValue, GetMantissa32(nValue));
printf("GetMantissa16(%f) = %u\n", nValue, GetMantissa16(nValue));
printf("GetMantissa32(%f) + GetMantissa16(%f) = %u\n", nValue, nValue, GetMantissa32(nValue) + GetMantissa16(nValue));
return 0;
}
실행 결과는 아래와 같다.
-= result in raw perspective =-
Mantissa32 in UINT = 4789685
Mantissa32 in float = 1.570975
-= result in my functions =-
mantissa of 3.141950 = 1.570975
GetMantissa32(3.141950) = 4789685
GetMantissa16(3.141950) = 584
GetMantissa32(3.141950) + GetMantissa16(3.141950) = 4790269
여기서 몇 가지를 주목할 필요가 있다.
1. 문제에서 입력값으로 3.14194989를 명시했지만, 애초에 32비트 부동소수점(float)에선 3.141950까지밖에 표현이 안 된다.
2. 유효숫자(Mantissa)인 1.570975는 \(\frac{3.1494989}{2}\)이다. 이 의미를 이해하는 것이 문제의 핵심 중 하나다.
3. GetMantissa32()의 결과값은 4789685인데, 이를 이진수로 표현하면 10010010001010110110101B이고,
GetMantissa16()의 결과값은 584인데, 이를 이진수로 표현하면 1001001000B이다.
상위 10비트의 값이 동일한데, 이 이유를 아는 것이 이 문제의 또 하나의 핵심이다.
4. 16비트 부동소수점은 실제 구현된 환경을 접하기 힘들어 정상 동작 여부를 검증하기 힘들다.
여기서는 위 3번을 통해 제대로 구현했다는 것을 확인할 수 있다.
영어로 숫자 센 것의 알파벳 수 세기 (프로젝트 오일러 #17) (0) | 2014.10.19 |
---|---|
BCD로 구현해본 Large sum (프로젝트 오일러 #13) (0) | 2014.10.19 |
네이버에 올라온 모 회사 입사 테스트 문제 풀이 3/4 (0) | 2014.10.12 |
네이버에 올라온 모 회사 입사 테스트 문제 풀이 2/4 (2) | 2014.10.12 |
네이버에 올라온 모 회사 입사 테스트 문제 풀이 1/4 (0) | 2014.10.12 |