2009-02-02 7 views
9

나는 특정 플랫폼에서 다음 코드 특정 컴파일러와부동 소수점 계산에서 과도한 정밀도를 처리하는 방법은 무엇입니까? 내 수치 시뮬레이션에서

double x; 
do { 
    x = /* some computation */; 
} while (x <= 0.0); 
/* some algorithm that requires x to be (precisely) larger than 0 */ 

(예를 들어 GCC)와 유사한 코드 (예를 들어, 리눅스, x87 수학)가 x를 double 정밀도보다 더 높은 계산 가능성이 있습니다 ("초과 정밀도"). (업데이트 : 여기서 정밀도에 대해 말하면 정확도 /와/range를 의미합니다. 이러한 상황에서는 다음 번에 x가 배정도로 반올림 됨으로써 0이되는 경우에도 비교 (x <= 0)가 false를 반환한다고 생각할 수 있습니다. . (x는 시간에 임의의 지점에서 내림되지 않는다는 보장이 없습니다.)

  • 휴대용 것을이 비교를 수행 할 수있는 방법이 있나요, 코드
  • 작동하는지
  • 에는 성능이 없습니다. t 및
  • 은 임의의 범위 (0, eps)를 제외하지 않습니까?

나는 (x < std::numeric_limits<double>::denorm_min())을 사용하려고 시도했지만 SSE2 수학을 사용하여 작업 할 때 루프가 상당히 느려진 것 같았습니다. (나는 비정규이 계산을 늦출 수 있다는 것을 알고 있지만, 나는 그들이 단지 주변에 이동하고 비교하는 속도가 느린 것으로 기대하지 않았다.)

업데이트 : 대안은 전에 메모리에 x를 강제로 volatile을 사용하는 것입니다 비교 예 작성하여 작성

} while (*((volatile double*)&x) <= 0.0); 

그러나 컴파일러에서 적용한 최적화 및 응용 프로그램에 따라이 솔루션은 눈에 띄는 오버 헤드가 발생할 수도 있습니다.

업데이트 : 모든 허용 오차의 문제는 상당히 임의적입니다. 즉 특정 응용 프로그램이나 컨텍스트에 따라 다릅니다. 나는 과도한 정밀도없이 비교를하고 싶다. 그래서 나는 추가 가정을하지 않거나 임의의 엡실론을 내 라이브러리 함수의 문서에 넣을 필요가 없다.

+0

흥미로운 질문은 처음으로 너무 많은 정확도에 대해 불평하는 사람을 처음 들어 본 적이 있습니다. – dsimcha

+0

비교에 명시 적 형변환을 추가하면 어떻게됩니까? 즉 ((double) x) <= 0.0'? – Christoph

+0

아마도 관련 : http://stackoverflow.com/questions/322797/problem-with-floating-point-precision-when-moving-from-i386-to-x8664 – Christoph

답변

1

당신이 적당한 기준을 정하는 지 궁금합니다. x < = 0은 예외인데 조건이지만 종료 조건은이 아니며 종료 조건을 만족시키기가 쉽습니다. 어쩌면 일부 내결함성이 충족 될 때 반복을 중지시키는 while 루프 내에 break 문이 있어야합니다. 예를 들어, 두 번의 연속적인 반복이 서로 충분히 가까울 때 많은 알고리즘이 종료됩니다.

+0

아니요,이 경우 실제로는 종결 조건 (또는 종결 조건의 논리적 부정)입니다. 물론 나중에 0으로 나누기가 있는지 여부를 확인할 수 있지만이 경우에는 (많은 경우에도) 0보다 작거나 같은 값을 반환하지 않는 함수가 필요합니다. – Stephan

0

GCC에는 논의중인 문제를 일으키는 -fexcess-precision 플래그가 있습니다. 여기에는 토론중인 문제점을 해결하는 -ffloat-store 플래그도 있습니다.

"부동 소수점 변수를 레지스터에 저장하지 마십시오. 부동 소수점 레지스터 (68881)가 두 배가 차지하는 것보다 더 정밀도를 유지하는 68000과 같은 시스템에서는 바람직하지 않은 과도한 정밀도가 발생합니다."

내가 그 솔루션은 성능에 영향을주지 않으므로 의심하지 않지만, 영향은 아마 지나치게 비용이. 임의의 인터넷 검색이 약 20 %를 소비합니다 제안합니다. 사실, 이 솔루션 거기 생각하지 않는다 모두 휴대용 및 칩에 과도한 정밀도를 사용하지 않으려면 종종 비 자유형 연산이 필요하기 때문에 성능상의 영향은 없습니다. 그러나 이것은 아마도 원하는 솔루션 일 것입니다.

+0

x86 기반 플랫폼의 경우 "-mfpmath = sse"를 사용하는 SSE2 지원은 부정적인 성능 영향없이 문제를 해결해야합니다. 그러나 비표준 컴파일러 옵션을 처방하는 것은 실제로 내 책에서 이식 할 수 없습니다. – Stephan

0

절대 값을 확인하십시오. 0 위, 아래 및 위의 엡실론 일 필요가 있습니다.

+0

do do 조건이 음수 값도 거부하지 않는다는 것을 (x Stephan

+0

문제는 일반적인 부동 소수점 정확성 문제가 아닙니다. 루프 외부에서 "x == 0"이 참일 때 원본 포스터에서 "(x> = 0)"이 false를 반환하는 것입니다. –

5

Arkadiy가 주석에 명시한대로 명시적인 캐스트 ((double)x) <= 0.0이어야합니다. 적어도 표준에 따르면.

C99 : TC3, 5.2.4.2.2 §8 : (모든 여분의 범위와 정밀도를 제거) 할당 및 캐스트를 제외하고

, 부동 피연산자 작업의 값과 평소에 따라 값 산술 변환 및 부동 상수의 범위와 정밀도가 형식에서 요구되는 것보다 클 수있는 형식으로 평가됩니다. 당신은 x86에서 GCC를 사용하는 경우 [...]


, 당신은, 더블, 확장 배정 밀도 골라 부동 소수점 연산의 정밀도를 설정하는 플래그 -mpc32, -mpc64-mpc80을 사용할 수 있습니다 .

+0

그러나 C99에 의존하는 것은 실제로 이식 가능하지 않습니다. 전혀 새로운 GCC 버전 만이 보장을받을 것입니다. – Stephan

+0

코드가 어떻게 이식성이 있어야하는지에 관해서는 모두 의문입니다. 나는 표준을 가지고 사용할 컴파일러를 테스트 할 것이다. 그들은 호환되지 않는 경우 makefile에 컴파일러 관련 플래그를 추가 할 것입니다 ... – Christoph

+0

추신 : "가장 최근의 GCC 버전 만이이 보증을 존중하며 모든 다른 컴파일러는 말할 것도 없습니다"- PS에서 " 당신은 이것을 시험해 보았을까요? 아니면 대부분의 (또는 심지어 모든) 현재 컴파일러에서 불완전한 C99 지원을 기반으로 한 가정입니까? – Christoph

2

귀하의 질문에 귀하는 volatile을 사용하지만 엄청난 성능 저하가있을 것이라고 말했습니다. 비교 중에 volatile 변수 만 사용하면 x을 레지스터에 보유 할 수 있습니까?

double x; /* might have excess precision */ 
volatile double x_dbl; /* guaranteed to be double precision */ 
do { 
    x = /* some computation */; 
    x_dbl = x; 
} while (x_dbl <= 0.0); 

명시 적으로 long double를 사용하여 작은 비정규 값과의 비교를 속도와 캐시이 값을, 즉

const long double dbl_denorm_min = static_cast<long double>(std::numeric_limits<double>::denorm_min()); 

을하고 비교할 수있는 경우도 확인해야

x < dbl_denorm_min 

괜찮은 컴파일러가이 작업을 자동으로 수행한다고 가정하지만, ...

+0

이것은 컴파일러와 특정 루프에 따라 조금씩 다릅니다. 그것은 비정상적인 값과 비교하는 것보다 빠르지 만 과도한 정밀도가없는 플랫폼에서는 눈에 띄는 오버 헤드가 발생합니다. – Stephan

+0

그럼에도 불구하고 잠재적 인 초과 정밀도를 가진 플랫폼에서'while (* ((volatile double *) & x) <= 0.0); '으로 확장되는 일부 매크로/선행 프로세서 정의를 살펴 보겠습니다. – Stephan

+0

비정규 비교는 SSE2 수학 만 속도가 느려지는데 적절한 긴 배가 사용 가능한 x87 수학이 아닙니다. – Stephan