|
일단 아래에 예로 든 방식은 좌에서 우로 비트를 배열한 것입니다.
비트열을 우에서 좌로 바꾸면 익숙한 방식이 될 것입니다.
부동 소수점 방식의 수 표현은 제시한 값을 단위 수들로 조합하여 만들게 됩니다.
이 때 오차가 발생하게 되어 지금과 같은 문제가 발생합니다.
여기서 단위수란 컴퓨터의 경우 2진수 체계이므로 1, 1/2, 1/4, 1/8... 이렇게 2의 제곱승으로 정밀해집니다.
이런 수는 float 형일 경우,
1비트 부호로 사용
8비트 지수로 사용
23비트 가수로 사용
여기서 23비트가 단위수를 만들어 정밀도를 결정하게 됩니다.
예를들어 숫자 5를 float 부동소수점으로 만들면 아래와 같아집니다.
좌에서 우로 주소가 증가하도록 나열했습니다.
00000000 00000000 00000101 00000010
제일 오른쪽이 부호 비트
0
그 이후 8비트
1 00000010
좌에서 우로 1, 2, 4, 8... 이렇게 증가하는걸 더하면 129가 나옵니다.
float 지수부는 부호비트를 두고있지 않음으로 비트에는 없는 숨겨진 수 -127을 계산하여 부호를 생성 합니다.
결국 지수 2가 됩니다. (129 - 127 = 2)
마지막 23 비트가 가수부이며 실제 부동소수 데이타 입니다.
00000000 00000000 0000010
좌에서 우로 주소가 증가한다는 기준이므로 오른쪽이 가장 큰수... 이런게 아니라..!!!
지금까지의 비트 순서대로...
오른쪽부터 1/2, 1/4.. 이렇게 2의 지수승으로 증가하는 정밀도를 담당하는 비트가 됩니다.
단 여기서 또 127 처럼 숨겨진 수 1이 있습니다.
우측 첫 자리 앞에 1이 있고 그 다음부터 1/2, 1/4, ... 이렇게 있게 되는 것입니다.
2진수는 0은 모든 진수에서 0이니 첫 수는 항상 1입니다. 1 ~ 2 사이의 수를 조합하여 만들게 됩니다.
결국
1 + (0 * (1/2)) + (1 * (1/4)) = 1.25
자... 이제 float 타입으로 숫자 5가 표현 되었습니다.
부호 : +
지수 : 2 --> 2진수의 지수 즉, 2^2 = 4
가수 : 1.25
최종 수 : 1.25 * 4 = 5
컴퓨터에서 정수와 실수는 근본적으로 다릅니다.
이런 특성을 고려해서 테스트하신 프로그램이 정상적으로 타입 케스팅 되려면...
더 정밀한 소수를 요구해야 비트열이 그 정밀도에 맞추어져서 계산되어 타입 캐스팅에서 원래수를 보장받게 됩니다.
(MS C++이나 GCC 등에서는 이럴경우 double로 살짝 편법 보정을 하게되어 그럴싸해 집니다. ㅋ 솔직한 C++빌더)
int a = 0
float b = 278.90001;
a = (int)(b*100.0);
이제 a 값은 2789가 됩니다.
- 추가 -
아... 이경우는 MS C++에도 같네요. ^^;
부동소수점 연산의 캐스팅 문제를 해결하려면 아무튼 가장 작은 유효 정밀도를 고려하도록 작은 수를 더해주면 해결됩니다.
float의 경우 소수 6자리(0.000001), double의 경우 소수 15자리(0.000000000000001)
물론 그렇게 되면 정밀도가 떨어지는 격이되니... 이런 특성을 고려해서 프로그래밍 하시는게 가장 좋습니다.
궁금이 님이 쓰신 글 :
: RAD Studio 2010 C++빌더 사용자입니다.
:
: int a = 0
: float b = 278.90;
:
: a = (int)(b*100.0);
:
: a=27890 이 돼야 할 것 같은데... 실제 결과값은 27889 가 됩니다.
: 혹시나 해서 float 대신 double을 사용해도 마찬가지입니다.
:
: 항상 저런 오류가 나는 것도 아니고... b값이 특정한 값일 경우만 저런 현상이 생기네요..
:
: 해결책이 있을까요?
|