float type 관련하여 문의 드립니다.
글쓴이: fctjsh / 작성시간: 금, 2013/08/09 - 1:54오후
아래 문제가 있습니다.
결과는 1000이 나와야 하지만 그렇지 않고 999.xxx 이런식으로 나옵니다.
float을 공부해본 결과 부동소수점 어쩌고 해서....유효자리수가 소수점 이하 7자리 정도 된다고 하네요.
그럼 당연히 0.1 x 10000은 소소점 이하 7자리가 안되니 계산이 잘되어 나와야 할 것 같은데 여전히 제대로 나오지 않네요.
왜 그런거죠?? 고수님들 자세한 답변 부탁 드릴께요.
벌써 3일째 이러고 있어요....
#include
void main()
{
float f = 0.1;
float sum = 0.0;
int i;
for( i=0; i<10000; i++ )
sum += f;
printf( "%f\n", sum );
}
Forums:
http://kldp.org/node/116672
http://kldp.org/node/116672
gilgil.net
float의 정확한 원리를 알고 있어야 이러한 상태의 발생을 막을 수 있습니다.
NEIS 사태에 대한 기술적인 설명 : http://www.gilgil.net/8358
www.gilgil.net
이런 글들을 보면서 느끼는 점은...
float 이랑 double 을 사용하지 말아야 겠다는 생각밖에 안드네요.
결국 100% 안전한 벙법은 없다는 것 같아 보여서...
float을 가지고 안전하게 설계 하려면 어떻게 해야 하는지에 대한 가이드 자료 같은건 없나요?
floating point 세계에서 a == b 라는
floating point 세계에서 a == b 라는 연산을 하면 안되는거죠.
이것만 안하면 ( explicitly/implicitly ) 충분히 "안전" 합니다.
어쩔 수 없는 겁니다.
1000 이전에 유효숫자가 10진수로 서너자리인 수가 나오고, 이들이 연산되면서 부정확해지는 듯 합니다.
가능하면 double 을 사용하시고, 실수 연산 결과에 대한 tolerance 를 미리 염두에 두는 것이 좋을 것입니다.
3D 렌더링이나 인코딩 프로그램 중에 GPU 연산을 지원하는 프로그램들이 있습니다.
CPU 연산은 배정밀도이고, 일반적으로 GPU 연산은 단정밀도인데,
일부 인코딩 프로그램에서 단정밀도를 사용한 결과가 상당히 안좋다는 말을 들은 적이 있습니다.
렌더링인 경우는, Luxrender 라는 렌더러를 배정밀도와 단정밀도로 모두 돌려 보았는데, 결과물의 차이를 눈으로 확인하기는 불가능했습니다.
10진수로 0.1자체가 2진수로 표현하기 어려운
10진수로 0.1자체가 2진수로 표현하기 어려운 수입니다.
double로도 마찬가지이고요.
0.1 == 0.1 이 false 라고 고민해야할 프로그램이라면 float를 쓰면 안되죠.
표현하기 어렵다기 보다는 0.1 이 이진수로는 무한
표현하기 어렵다기 보다는 0.1 이 이진수로는 무한 소수이기 때문에 정확히 표현할 수 없다고 해야겠죠.
0.5는 이진수로 한자리로 간단히 표현되기 때문에, 본문의 연산을 하면 정확한 결과가 나옵니다.
float, double 의 경우에도 등호나 부등호 연산이 필요한 경우가 있습니다.
이 경우는 경우마다 별도로 허용값을 정해 등호 연산을 정의해야 합니다.
이런! 0.1이 이진수로 무한 소수였구나... 이
이런! 0.1이 이진수로 무한 소수였구나...
이 문제에서는 이게 근원적 문제였군요.
징하게 빡시네요..
윗분들이 이유를 다 말해 주셨는데 좀
윗분들이 이유를 다 말해 주셨는데 좀 보세요.
0.1, 0.2, 0.3, 0.4 등은 이진수로는 무한소수이기 때문에 이런 수를 가지고 계산하면 유효 숫자로 뒤가 짤려서 덧셈이 부정확해지는 거고,
0.5, 0.25 등은 이진수로 간단한 유한 소수이기 때문에 정확한 결과가 나옵니다.
계산을 다르게 더하는게 아니에요.
당연 저렇게 되지 않을 것이란 건 아는데..
내부 비트 연산이 어떻게 되는지 궁금해서 올린 글인데
질문을 잘못된 방법으로 했네요...죄송합니다.
0.1
0 01111011 1001100110011001100110
0.2
0 01111100 1001100110011001100110
0.3
0 01111101 0011001100110011001101
실제 float은 내부적으로 위와 같은 4바이트로 저장 되는데...
당연 컴터니 비트 연산을 할 것 같고..
0.1과 0.2 가 어떻게 더해져 0.3 이 나오는지 궁금해서요..
무지해서 죄송..ㅜㅜ
실수의 체계는 정수의 체계와는 다릅니다. 일반적으로
실수의 체계는 정수의 체계와는 다릅니다. 일반적으로 실수는 s(sign), e(exponent), f(fraction) 부분으로 나뉩니다.
http://en.wikipedia.org/wiki/Single_precision_floating-point_format
즉 s, f, e가 주어 질 때 실수의 값은 수학 공식으로 써 보자면 다음과 같습니다.
value = 2 ^ e * f (s가 0이면 양수, 1이면 음수)
덧셈의 경우에는 2개의 숫자의 exponent를 먼저 맞춘 다음 fraction 부분을 더하게 되겠죠.
실수(float)의 sign, exponent, fraction을 출력해 주는 프로그램을 작성한 것이 있으니 참고하시기 바랍니다.
http://www.gilgil.net/11340
www.gilgil.net
제가 궁금한건.....
위의 숫자들은 실수 float을 union을 사용하여 출력해주는 프로그램을 통하여 이미 출력된 내용이에요.
제가 궁금한건 아래 말씀 하신 이 내용의 과정을 보고 싶어서요....
"덧셈의 경우에는 2개의 숫자의 exponent를 먼저 맞춘 다음 fraction 부분을 더하게 되겠죠."
gilgil.net
구글링해 보니 금방 나오네요.
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BinMath/addFloat.html
요즘 컴퓨터 환경에서는 위 URL에서 표현된 실수 연산 계산 방식을 CPU 혹은 co-processor에서 처리해 주고 있기 때문에 SW 프로그래머가 꼭 알아야 할 필요는 없다고 봅니다.
www.gilgil.net
0.1(DEC) =
0.1(DEC) = 0.00011001100110011...(BIN)
0.2(DEC) = 0.00110011001100110...(BIN)
+_____________________________________
0.3(DEC) = 0.010011001100110.....(BIN)
감사합니다..
꾸벅..
댓글 달기