2014-04-11 5 views
1

대부분의 피직스 엔진은 객체의 궤도를 얼마나 멀리 밟았는지 나타내는 0.0에서 1.0 사이의 인수를 반환하는 객체 궤도 추적을 지원합니다.과소 평가 된 부동 소수점 인수

내가 염려하는 문제는 그 궤적의 요인에 의해 객체를 움직이면 그 위치가 히트하고 멈추기로되어 있던 경계를 지나가는 경우입니다 (부동 소수점 올림 때문에).

예를 들어,이 문제가 발생할 때까지 무작위로 시도한 C 프로그램을 만들었습니다. (나는 극단적 인 움직임이 적은 것들을 경험했지만, 큰 부동 소수점에만 국한되지는 않습니다.) :

float start  = 4884361.0f; 
float wall  = 37961976.0f; 
float end  = 1398674432.0f; 
float time  = (wall - start)/(end - start); 
float new_pos = start + time * (end - start); 
printf("We hit %f, but moving left us at %f.\n", wall, new_pos); 

그리고이 경우는 출력한다 :

We hit 37961976.000000, but moving left us at 37961980.000000. 그래서 위치가 벽 위치를 넘어 이동 지금은 객체가 벽 안에 갇혀있다.

계수를 생성하거나 부동 소수점 오류가 항상 모든 가능한 값의 실제 값을 언더 슈팅하도록 요소 승수를 수행하는 방법이 있습니까?

+1

부동 소수점 동작을 변경하는 대신 new_pos를 계산할 때 한계를 고려하는 래퍼 함수 만 작성하는 것이 좋습니다. wrapper 내부에서, 여러분은 심지어 "double"으로 승진 할 수 있고 더 큰 정밀도로 에러를 볼 수 있습니다. – cklin

+1

의역을 말하자면 반올림 오류가 정확한 값보다 높지는 않은지 확인하고 싶습니까? –

+0

@cklink : 실제로 '시간'은 벽이 축과 정렬되지 않았기 때문에 정상 투영에 의해 계산되므로 가능하지 않을 수 있습니다. 따라서 new_pos를 계산할 때 위치 제한에 대한 실질적인 개념은 없습니다 '. – Jengerer

답변

1

계산 된 값은 다음 (또는 거의 다음에) 부동 소수점 숫자입니다. 우리는 float 정밀도의 한계에 있습니다. 답변이 또는 예상 답변 한쪽입니다 보장하기 위해, 다수가

1) 높은 중간 정밀 접근이 있습니다 : (

float start  = 4884361.0f; 
float wall  = 37961976.0f; 
float end  = 1398674432.0f; 
double time  = ((double)wall - start)/((double)end - start); 
float new_pos = start + time * ((double)end - start); 

) 훨씬 더 자주 정답을 마련한다 2) 논리 : (부드러운 해킹)

: (이 절대적으로

if (new_pos > wall) new_pos = wall; 

3)는 약간 낮은 시간 값을 사용) 작동합니다 9,442,973,210

4) 변경 FP 0으로 둥글게 라운딩 모드하면 : 프로 & 단점마다의

static const float factor = 0.99999; 
float new_pos = start + factor*time * (end - start); 

많은 (이는 비록 큰 영향)

fesetround(FE_TOWARDZERO); 

5) 단순한 계수를 가질 수있다 접근.

+1

@Jengerer 참조 변경을 시도 할 수도 있습니다. 'new_wall' 0.0과'new_start = start-wall'을 만드십시오. 이것이 어떻게 도움이 될지 모르지만 0.0에 가까워 질수록 정확도가 높아집니다. – chux

+0

다시 한번 감사드립니다. 나는'nextafterf()'가 문제를 충분히 해결한다고 생각한다. 'start','wall','end'에 대한 float 값의 모든 가능한 트리플에 대해 작동하는지 확인하려면 2 년의 계산이 필요합니다. 그러나 가능한 값 I의 더 작은 영역으로 훌륭하게 작동하는 것 같습니다. 시도했다. 내 시간 값이 0과 1 사이에 있음을 알고 있기 때문에 float의 int 표현을 1 씩 줄이는'nextafterf'의 더 빠른 버전을 구현할 수 있습니다 (이는'nextafter'가 해당 값 범위에서하는 것입니다). – Jengerer