[C++] float형 실수를 ieee 754 표준형의 형태로 저장하려는데 문제가 있습니다.
글쓴이: kjw4569 / 작성시간: 수, 2017/10/04 - 6:25오후
cin >> floatNum unsigned __int64 intNum = (unsigned __int64)floatNum; //정수부 floatNum -= (float)intNum; //소수부만 남김 for (i = 0; i < len; i++) { //정수부를 이진수로 변환 if (intNum == 0) break; arr[i] = intNum % 2; intNum /= 2; }
사용자로부터 실수를 입력받아 floatNum에 저장합니다.
그리고 floatNum의 정수부와 실수부를 분리해서 각각 이진수로 bool 배열에 저장하려고 합니다.
문제는 아주 큰 수가 입력되었을 경우입니다.
1번 줄에서 부호없는 8바이트 정수형을 써봐도 최대 2^64까지밖에 저장이 안 되네요. 실제로 float형은 2^128까지 표현할 수 있는데 말이죠.
디버그 걸어놓고 floatNum을 살펴보면 큰 수 까지도 제대로 저장이 되는걸 보면 cin 함수는 도대체 어떤 방식으로 작동하는 건지 궁금하기도 하고..
어떤 방법을 써야 할까요?
(* 모호한 표현이 있어 제목을 수정했습니다.)
Forums:
"float형은 2^128까지 표현할 수 있는데
8바이트 정수형을 쓰면 최대 2^64까지밖에 저장이 안 되는게 당연하죠.
float형이 2^128까지 표현할 수 있는 것과는 무관합니다.
실수는 지수부와 가수부로 나누는 방식으로 아주 작은 수와 아주 큰 수를 표현하는 것입니다.
따라서 정수로 표현할 수 없는 범위의 실수를 정수로 변환하면 당연히 오버플로우가 발생하겠죠.
...
그나저나 float형 변수는 이미 데이터를 IEEE 754 표준에 따라 저장하고 있는 변수입니다.
float를 IEEE-754로 *변환해서* 저장한다는 말은 뭘 하시려는 건지 잘 이해가 안 가는데요.
이진수 형태로 bool 배열에 저장하려고 합니다.
예를 들어 7.0의 경우, 1.11×2^2 이므로 32 길이의 bool 배열에
부호 지수 가수
0 | 10000001 | 1100 0000 0000 0000 0000 000
의 형태로 저장하려는 것입니다.
void*로 캐스팅한 다음에 unsigned integer로 캐스팅하세요
unsigned int intNum = *((unsigned int*) ((void*)&floatNum));
설명) 두 번째 줄에서 unsigned int로 캐스팅하면 캐스팅룰에 의해 2^64를 초과하는 값에 대해서는 값이 보존되지 않습니다.
floatNum의 주소를 void*로 캐스팅하면 타입 정보가 사라지고, 여기서 다시 (unsigned int*)로 캐스팅하면 floatNum의 주소를 unsigned int 타입의 4바이트 데이터가 들어있는 것으로 간주합니다. 마지막으로 디리퍼런싱해주면 끝나겠죠.
실수의 구조를 무시하고 그대로 캐스팅한다고 해서,
실수의 구조를 무시하고 그대로 캐스팅한다고 해서, 지수부가 저장되는 것은 아닙니다.
글을 상상으로 쓰지 마세요.
...
제가 뭘 놓치는 걸 수도 있지만, 실수의 bit pattern을 그대로 읽으려면 저런 식으로 많이들 할 텐데요.
* 물론 C의 undefined behavior를 사용하는 것이기 때문에 최적화 옵션을 주면 코드가 나가리 날 수 있겠습니다만.
이렇게 비트 단위에서 추출하는게 가장 확실한 방법이긴 한데
제가 과제를 수행하고 있는지라..
아래와 같은 로직을 사용하지 않으면 (정수부는 2로 나누고, 소수부는 2를 곱해나가는)
교수님께 반칙이라고 지적을 당할 것 같습니다.
셀프 답변 해봅니다.
https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/vfscanf.c;h=e0d224530cc67498c3fa5b37838d5bdcdf08eb28;hb=HEAD#l2332
scanf 소스를 찾았는데오, strtof 함수를 쓰는걸 보니 역시 정수를 통째로 받으면 안 되고 문자열로 입력받도록 수정해야겠습니다.
좀 복잡해지겠네요.
그냥 실수의 해당 비트들을 추출해서 비트 연산으로
그냥 실수의 해당 비트들을 추출해서 비트 연산으로 간단하게 되지 않나요?
바로 윗 댓글에도 적었지만
과제를 수행중이기 때문에.. 교수님께 반칙이라고 지적을 당할 것 같습니다.
구체적인 상황에 따라 다르긴 합니다만, 일반적으로
구체적인 상황에 따라 다르긴 합니다만, 일반적으로 생각해 봤을 때 십진 실수를 문자열로 입력받아서
그걸 IEEE754 이진 부동소수점 포맷으로 변환하는 건 과제 치고는 제법 번거로운 코드가 될 겁니다.
물론 하려고 들면 못 할 건 없는 일이긴 합니다만, 저라면 그걸 시작하기 전에 담당 조교님께 문의를 드린다던가 해서 과제 취지를 분명히 확인해보고 시작할 것 같은데요.
시간이 많으셔서 한 번 해보고 싶으시다면 물론 애써 말릴 생각은 없습니다. 좋은 연습이기는 하니까요.
댓글 달기