2010-04-28 4 views
14

문제를 간단히 말하면 에 a/(b - c)이라는 표현식을 계산하려고한다고 가정 해 봅시다. "엡실론"은 실제로 부동 소수점 계산에서 어떤 것도 보장합니까?

bc가 동일한에 있다면 내가 확인하실 수 있습니다, 결과는 의미가 있는지 확인하려면 다음

float EPS = std::numeric_limits<float>::epsilon(); 
if ((b - c) > EPS || (c - b) > EPS) 
{ 
    return a/(b - c); 
} 

을하지만 내 테스트는 의미있는 결과도 제공하기 위해 실패하지 하나를 보장하는 것만으로는 충분하지 않습니다 보여 가능한 경우 결과.

사례 1 :

a = 1.0f; 
b = 0.00000003f; 
c = 0.00000002f; 

결과 : (가) 조건이 충족되지 않으면,하지만 표현 (수레 '정밀도로) 올바른 결과 100,000,008을 생산한다.

사례 2 :

a = 1e33f; 
b = 0.000003; 
c = 0.000002; 

결과 : (가) 조건이 충족되는 경우,하지만 표현이 의미있는 결과 +1.#INF00을하지 생성합니다.

const float INF = numeric_limits<float>::infinity(); 
float x = a/(b - c); 
if (-INF < x && x < INF) 
{ 
    return x; 
} 

그러나 왜 모두가 엡실론 사용하는 것이 좋다 말하고 엡실론은 다음 때문이다 :

내가 아니라 인수, 훨씬 더 신뢰할 수있는 결과를 확인하는 것으로?

답변

18

"float를 다룰 때 엡실론을 사용해야합니다."는 일반적으로 (0이 아닌) 비교를 위해 부동 소수점 계산을 겉으로 드러내는 프로그래머의 무례한 반응입니다.

반올림 오류 전파를 최소화하는 방법을 알려주지 않으므로 취소 또는 흡수 문제를 피하는 방법을 알려주지 않으며 문제가 실제로 두 개의 수레, 엡실론의 어떤 가치가 당신이하고있는 일에 맞는지 알려주지 않습니다..

What Every Computer Scientist Should Know About Floating-Point Arithmetic을 읽지 않았 으면 좋은 출발점입니다. 더 나아가, 예제에서 나누기 결과의 정밀도에 관심이있는 경우 b-c이 얼마나 부정확한지 추정해야합니다. 이전 반올림 오류입니다. 실제로는 b-c이 작 으면 작은 절대 오류가 발생합니다. 결과에 대한 절대적인 오차가 크다. 귀하의 우려가 부문 만 넘치지 않아야한다면, 결과에 대한 귀하의 테스트가 옳습니다.부동 소수점 숫자가있는 Null divisor를 테스트 할 이유가 없습니다. 결과의 오버플로를 테스트합니다. 제수가 null 인 경우와 제수가 너무 작아서 결과를 표현할 수없는 경우를 모두 캡처합니다. 어떤 정밀도.

반올림 오류 전파에는 수동으로 수행하는 지루한 작업이므로 예상 오류를 방지 할 수있는 specialized analyzers이 있습니다.

+5

"엡실론의 어떤 가치가 당신이하고있는 일에 맞는지 알려주지 않습니다."이 문장을 더 강조하십시오. 정말 중요합니다. –

2

엡실론은 반올림 오류가있는 두 개의 숫자가 "동등한"것으로 간주 될만큼 충분히 가까운 지 여부를 확인하는 데 사용됩니다. fabs(b/c - 1) < EPSfabs(b-c) < EPS보다 더 테스트하고 IEEE 플로트 —의 디자인 덕분에 abs(*(int*)&b - *(int*)&c) < EPSI (EPSI가 작은 정수인 경우) 덕분에 더 나은 —을 테스트하는 것이 더 낫습니다.

귀하의 문제는 성격이 다르므로 입력 사항이 아닌 결과를 테스트하는 것이 좋습니다.

+2

"엄격한 앨리어싱 규칙"군중은 당신의'* (int *) &'구조에 대해 말할 것이있다. 필자는 개인적으로 기존 사례에 대한 벤치 마크 타이밍과 언어의 의미에 대한 프로그래머의 광범위한 이해를 강조하는 컴파일러의 태도에 동의하지 않지만 요점은 다음과 같습니다. 코드가 현대 컴파일러에 의해 잘못 컴파일됩니다. –

+0

코멘트 주셔서 감사합니다, 파스칼. 나는 이것을 모두 하나의 묶음으로 감쌀 수 있지만, 그러한 접선 점에 대해서는 너무 많은 자세한 정보가 될 것입니다. –

+0

조심성있는'* (int *) & '트릭 : 파스칼 문제 유형 파스칼의 언급과는 별개로, 파스칼이 언급하는 것 이외에도 b와 c가 매우 비슷하지만 반대 기호 (예 : b = 2e-45f , c = -0.0f) 그러면 테스트가 실패합니다. –