부동 소수점 숫자의 상대 비교


10

나는 수치 기능이 f(x, y)구현 몇 가지 공식과 나는 그것이 모든 매개 변수 조합에 대한 분석 표현에 대한 올바른지 확인하려는 이중 부동 소수점 숫자 반환 xy나는에 관심이 있습니다. 무엇을 계산하고 비교하는 적절한 방법입니다 분석 부동 소수점 숫자?

두 숫자가 a및 라고 가정 해 보겠습니다 b. 지금까지 절대 abs(a-b) < eps( abs(a-b)/max(abs(a), abs(b)) < eps) 오류 와 상대 ( ) 오류가 모두 eps 미만 인지 확인했습니다 . 그렇게하면 숫자가 1e-20 정도라고해도 수치 부정확성을 잡을 수 있습니다.

그러나 오늘 문제를 발견했습니다. 숫자 값 a과 분석 값 b은 다음 과 같습니다.

In [47]: a                                                                     
Out[47]: 5.9781943146790832e-322

In [48]: b                                                                     
Out[48]: 6.0276008792632078e-322

In [50]: abs(a-b)                                                              
Out[50]: 4.9406564584124654e-324

In [52]: abs(a-b) / max(a, b)                                                  
Out[52]: 0.0081967213114754103

따라서 절대 오차 [50]은 (분명히) 작지만 상대 오차 [52]는 큽니다. 그래서 프로그램에 버그가 있다고 생각했습니다. 디버깅을 통해 이러한 숫자가 비정상 임을 깨달았습니다 . 따라서 적절한 상대 비교를 수행하기 위해 다음 루틴을 작성했습니다.

real(dp) elemental function rel_error(a, b) result(r)
real(dp), intent(in) :: a, b
real(dp) :: m, d
d = abs(a-b)
m = max(abs(a), abs(b))
if (d < tiny(1._dp)) then
    r = 0
else
    r = d / m
end if
end function

어디 tiny(1._dp)내 컴퓨터에 2.22507385850720138E-308을 반환합니다. 이제 모든 것이 작동하고 상대 오류로 단순히 0을 얻습니다. 특히, 상기 상대 오차 [52]는 틀리며, 이는 비정규 수의 정확도가 불충분하기 때문입니다. 내 구현입니까rel_error함수의 정확합니까? abs(a-b)작은 것보다 작은 지 확인하고 (= 비정상) 0을 반환해야합니까? 아니면 다른 조합을 확인해야 max(abs(a), abs(b))합니까?

나는 "적절한"방법이 무엇인지 알고 싶습니다.

답변:


11

직접 사용하여 비정규을 확인할 수 있습니다 isnormal()에서 math.h(나중에 C99 이상, POSIX.1 또는). 포트란에서 모듈이ieee_arithmetic 을 사용할 수있는 경우ieee_is_normal() . 퍼지 평등에 대해 더 정확하게하려면 비정규의 부동 소수점 표현을 고려해야하고 결과가 충분하다는 의미를 결정해야합니다.

더 중요한 것은 두 결과가 모두 정확하다고 생각하려면 중간 단계에서 너무 많은 숫자를 잃지 않았 음을 확신해야합니다. 비정상적으로 계산하는 것은 일반적으로 신뢰할 수 없으며 알고리즘의 내부 크기를 조정하여 피해야합니다. 내부 스케일링이 성공적으로 수행되도록하려면 부동 소수점 예외를 활성화하는 것이 좋습니다.feenableexcept() C99 또는 ieee_arithmeticFortran 의 모듈 과 함께 .

부동 소수점 예외에서 발생하는 신호를 응용 프로그램에서 잡을 수는 있지만 하드웨어 커널을 재설정하려고 시도한 모든 커널 fetestexcept()은 유용한 결과를 반환하지 않습니다. 로 실행하면 -fp_trapPETSc 프로그램은 부동 소수점 오류가 발생하면 기본적으로 스택 추적을 인쇄하지만 문제를 일으키는 행을 식별하지는 않습니다. 디버거에서 실행하는 경우 디버거는 하드웨어 플래그를 유지하고 문제가되는 식에서 중단됩니다. fetestexcept결과가 다음 플래그의 비트 단위 OR 인 디버거에서 호출하여 정확한 이유를 확인할 수 있습니다 (값은 시스템마다 다를 수 있습니다 ( fenv.h이 값은 glibc가있는 x86-64에 해당) 참조).

  • FE_INVALID = 0x1
  • FE_DIVBYZERO = 0x4
  • FE_OVERFLOW = 0x8
  • FE_UNDERFLOW = 0x10
  • FE_INEXACT = 0x20

훌륭한 답변에 감사드립니다. 점근 요법에서 비교하는 분석 표현은 exp(log_gamma(m+0.5_dp) - (m+0.5_dp)*log(t)) / 2m = 234, t = 2000입니다. 내가 증가함에 따라 그것은 빨리 0으로 간다 m. 숫자 루틴이 "올바른"숫자 (0을 반환하는 것도 괜찮음)를 12 자리 이상의 유효 숫자로 반환하도록하고 싶습니다. 따라서 계산에서 비정규 숫자를 반환하면 단순히 0이며 문제가 없습니다. 따라서 비교 루틴 만 강력하게해야합니다.
Ondřej Čertík

5

Donald Knuth는 "컴퓨터 프로그래밍 기술"의 2 권 "Seminumerical algorithms"에서 부동 소수점 비교 알고리즘을 제안했습니다. 그것은 C에 의해 Th에 의해 구현되었습니다. Belding ( fcmp 패키지 참조 )이며 GSL 에서 사용할 수 있습니다 .


2
다음은 Fortran 구현입니다 : gist.github.com/3776847 , 어쨌든 비정상적인 숫자를 명시 적으로 처리해야합니다. 그렇지 않으면 상대 오류와 거의 동일하다고 생각하지만 유일한 차이점은abs(a-b)/max(a, b) < eps , 우리가 abs(a-b)/2**exponent(max(a, b)) < eps거의 단지에서 가수을 삭제하는, max(a, b)그래서 내 의견의 차이는 무시할 수있다.
Ondřej Čertík

5

최적으로 반올림 된 비정규 화 된 숫자는 실제로 상대적 오류가 높을 수 있습니다. (상대 오류라고 부르면서 0으로 플러시하는 것은 잘못된 것입니다.)

그러나 0에 가까워지면 상대 침식 계산은 의미가 없습니다.

따라서 비정규 화 된 숫자에 도달하기 전에도 절대 정확도 (이 경우 보장하려는 것)로 전환해야합니다.

와이엑스|와이엑스|에스+아르 자형이자형최대(|엑스|,|와이|) . relacc = 1e-12 및 absacc = 1e-150으로 말하십시오.

그런 다음 코드 사용자는 실제 정확도를 정확하게 알고 있습니다.


상대 오차를 거의 0에 가깝게 계산하는 것이 의미가없는 것입니까? 나는 그것이 어떤 이유로 든 정확성의 상실이있는 경우에만 의미가 없다고 생각합니다. 예를 들어 두 개의 큰 숫자를 빼는 것과 같은 수치 문제로 인해 x <1e-150의 정확도가 손실되면 맞습니다. 내 경우에는 그러나 숫자가 비정상적인 숫자에 도달 할 때를 제외하고는 숫자가 0까지 정확 해 보입니다. 내 경우에는 absacc = 1e-320 정도이며 abs(a-b) < tiny(1._dp)위와 같이 확인할 수 있습니다 .
Ondřej Čertík

@ OndřejČertík :이 경우 1e-150을 1e-300 또는 검증 할 수있는 범위로 바꾸십시오. 어쨌든 0에 매우 가까운 경우 절대 오류가 발생하며 상대 오류를 0으로 선언하기보다는 오류 주장에이를 반영해야합니다.
Arnold Neumaier

내가 참조. 나는 모든 것이 더 높은 숫자에 대해 작동하는지 확인할 수 있습니다 tiny(1._dp)=2.22507385850720138E-308(이전 의견에서 실수를 한 경우 1e-320이 아니라 2e-308입니다). 그래서 이것은 내 절대 오류입니다. 그런 다음 상대 오류를 비교해야합니다. 나는 당신의 요점을보고, 당신이 옳다고 생각합니다. 감사!
Ondřej Čertík

1
@ OndřejČertík : absacc에 대한 추가 상대 오류를 찾으려면 최대 |와이엑스|에스최대(|엑스|,|와이|)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.