부동 소수점 숫자의 정확도 문제를 처리합니다
-
09-09-2019 - |
문제
내 컴퓨터의 부동 소수점 숫자의 내부 표현의 결과 인 것처럼 보이는 정확도 문제를 극복하는 방법이 있는지 궁금합니다.
명확성을 위해 문제는 다음과 같이 요약됩니다.
// str is "4.600"; atof( str ) is 4.5999999999999996
double mw = atof( str )
// The variables used in the columns calculation below are:
//
// mw = 4.5999999999999996
// p = 0.2
// g = 0.2
// h = 1 (integer)
int columns = (int) ( ( mw - ( h * 11 * p ) ) / ( ( h * 11 * p ) + g ) ) + 1;
정수 유형으로 캐스팅하기 전에 열 계산 결과는 1.9999999999999996입니다. 따라서 지금까지 2.0의 원하는 결과와는 거리가 멀다.
모든 제안이 가장 환영합니다.
해결책
부동 소수점 번호를 정수로 반올림하는 매우 간단하고 효과적인 방법 :
int rounded = (int)(f + 0.5);
참고 : 이것은 경우에만 작동합니다 f
항상 긍정적입니다. (감사합니다 J Random Hacker)
다른 팁
플로팅 포인트 산술 엄격한 평등을 사용하면 거의 의미가 없습니다. 일반적으로 허용 가능한 다양한 값과 비교하고 싶습니다.
일부 값은 할 수 있습니다 ~ 아니다 플로팅 포인트 블루스로 정확하게 표현됩니다.
몰수 문제가 없습니다.
결과 (1.999999999999996)는 수학적 결과 (2)의 1E-16 마진과 다릅니다. 입력 "4.600"을 고려하여 매우 정확합니다.
물론 반올림 문제가 있습니다. C ++의 기본 반올림은 잘림입니다. KIP의 솔루션과 비슷한 것을 원합니다. 세부 사항은 정확한 도메인에 따라 round(-x)== - round(x)
?
당신이 그것을 읽지 않았다면, 제목입니다 이 종이 정말 정확합니다. 현대 컴퓨터의 부동 소수점 산술의 기본 사항, 일부 함정 및 그들이하는 방식에 대한 설명에 대한 설명에 대해 자세히 알아 보려면 읽어보십시오.
정확도가 정말로 중요하다면 플로팅 포인트가 아닌 이중 정밀 부동 소수점 번호를 사용하는 것을 고려해야합니다. 당신의 질문에서 당신이 이미있는 것 같습니다. 그러나 특정 값을 확인하는 데 여전히 문제가 있습니다. (0에 대해 값을 확인한다고 가정 할 때)의 줄을 따라 코드가 필요합니다.
if (abs(value) < epsilon)
{
// Do Stuff
}
여기서 "Epsilon"은 작지만 0이 아닌 값입니다.
컴퓨터에서는 부동 소수점 번호가 정확하지 않습니다. 그들은 항상 가까운 근사입니다. (1E-16은 가깝습니다.)
때로는 보지 못하는 숨겨진 비트가 있습니다. 때로는 대수의 기본 규칙이 더 이상 적용되지 않습니다 : a*b! = b*a. 때로는 메모리에 레지스터를 비교하면 이러한 미묘한 차이가 나타납니다. 또는 수학 공동 프로세서 대 런타임 플로팅 포인트 라이브러리 사용. (나는이 waayyy 너무 오래 해왔다.)
C99는 다음과 같이 정의합니다 수학)
double round(double x);
float roundf(float x);
long double roundl(long double x);
.
또는 직접 굴릴 수 있습니다.
template<class TYPE> inline int ROUND(const TYPE & x)
{ return int( (x > 0) ? (x + 0.5) : (x - 0.5) ); }
플로팅 포인트 동등성의 경우 다음을 시도하십시오.
template<class TYPE> inline TYPE ABS(const TYPE & t)
{ return t>=0 ? t : - t; }
template<class TYPE> inline bool FLOAT_EQUIVALENT(
const TYPE & x, const TYPE & y, const TYPE & epsilon )
{ return ABS(x-y) < epsilon; }
소수 사용 : 타협장 ++