차이가 기계 정밀도보다 작은 지 확인하는 올바른 / 표준 방법은 무엇입니까?


36

얻은 차이가 기계 정밀도보다 높은지 확인 해야하는 상황이 종종 발생합니다. 이 목적을 위해 R은 편리한 변수를 가지고 있습니다 : .Machine$double.eps. 그러나이 값 사용에 대한 지침을 R 소스 코드로 전환하면 여러 가지 다른 패턴이 나타납니다.

다음은 stats라이브러리 의 몇 가지 예입니다 .

t.test.R

if(stderr < 10 *.Machine$double.eps * abs(mx))

chisq.test.R

if(abs(sum(p)-1) > sqrt(.Machine$double.eps))

통합 .R

rel.tol < max(50*.Machine$double.eps, 0.5e-28)

lm.influence.R

e[abs(e) < 100 * .Machine$double.eps * median(abs(e))] <- 0

princomp.R

if (any(ev[neg] < - 9 * .Machine$double.eps * ev[1L]))

기타

질문

  1. 어떻게 그 다른 모든 뒤에 추론 이해할 수있는 10 *, 100 *, 50 *sqrt()수정을?
  2. .Machine$double.eps정밀도 문제로 인한 차이 조정 에 대한 지침이 있습니까?



6
따라서 두 게시물 모두 "합리적인 확실성 수준"은 응용 프로그램에 따라 다릅니다. 사례 연구로서 R-devel에서이 게시물을 확인할 수 있습니다 . "Aha! 숫자 자체가 두 자리 숫자 일 때 기계 정밀도의 100 배는 아닙니다." (피터 Dalgaard의 R 코어 팀의 멤버)
헨릭

1
@ KarolisKoncevičius, 나는 그것이 그렇게 간단하다고 생각하지 않습니다. 부동 소수점 수학에 존재하는 일반적인 오류 및 그에 대해 얼마나 많은 연산을 수행하는지와 관련이 있습니다. 부동 소수점 숫자와 단순히 비교하는 경우을 사용하십시오 double.eps. 부동 소수점 숫자에 대해 여러 작업을 수행하는 경우 오류 허용 오차도 조정해야합니다. 이것이 all.equaltolerance인수를 제공하는 이유 입니다.
Joseph Wood

1
또한 R의 차세대 기능 구현에 대해 살펴보면 다음으로 큰 두 배의 숫자를 얻을 수 있습니다.
GKi

답변:


4

기계 정밀도 double는 현재 값 에 따라 다릅니다. .Machine$double.eps값이 1 인 경우 정밀도를 제공합니다. C 함수 nextAfter를 사용하여 다른 값의 기계 정밀도를 얻을 수 있습니다.

library(Rcpp)
cppFunction("double getPrec(double x) {
  return nextafter(x, std::numeric_limits<double>::infinity()) - x;}")

(pr <- getPrec(1))
#[1] 2.220446e-16
1 + pr == 1
#[1] FALSE
1 + pr/2 == 1
#[1] TRUE
1 + (pr/2 + getPrec(pr/2)) == 1
#[1] FALSE
1 + pr/2 + pr/2 == 1
#[1] TRUE
pr/2 + pr/2 + 1 == 1
#[1] FALSE

값을 추가 a값은 b변경되지 않습니다 ba입니다 <= 그것의 기계 정밀도의 절반. 차이가 기계 정밀도보다 작은 지 확인하십시오 <. 수정자는 추가가 변경을 표시하지 않은 일반적인 경우를 고려할 수 있습니다.

에서 R 기계의 정밀도로 추정 할 수있다 :

getPrecR <- function(x) {
  y <- log2(pmax(.Machine$double.xmin, abs(x)))
  ifelse(x < 0 & floor(y) == y, 2^(y-1), 2^floor(y)) * .Machine$double.eps
}
getPrecR(1)
#[1] 2.220446e-16

double값은 범위를 나타냅니다. 간단한 추가를 위해 결과 범위는 각 소환의 범위와 합계의 범위에 따라 다릅니다.

library(Rcpp)
cppFunction("std::vector<double> getRange(double x) {return std::vector<double>{
   (nextafter(x, -std::numeric_limits<double>::infinity()) - x)/2.
 , (nextafter(x, std::numeric_limits<double>::infinity()) - x)/2.};}")

x <- 2^54 - 2
getRange(x)
#[1] -1  1
y <- 4.1
getRange(y)
#[1] -4.440892e-16  4.440892e-16
z <- x + y
getRange(z)
#[1] -2  2
z - x - y #Should be 0
#[1] 1.9

2^54 - 2.9 + 4.1 - (2^54 + 5.9) #Should be -4.7
#[1] 0
2^54 - 2.9 == 2^54 - 2      #Gain 0.9
2^54 - 2 + 4.1 == 2^54 + 4  #Gain 1.9
2^54 + 5.9 == 2^54 + 4      #Gain 1.9

더 높은 정밀도 Rmpfr를 위해 사용될 수있다.

library(Rmpfr)
mpfr("2", 1024L)^54 - 2.9 + 4.1 - (mpfr("2", 1024L)^54 + 5.9)
#[1] -4.700000000000000621724893790087662637233734130859375

정수로 변환 할 gmp수있는 경우 (Rmpfr에있는) 사용할 수 있습니다.

library(gmp)
as.bigz("2")^54 * 10 - 29 + 41 - (as.bigz("2")^54 * 10 + 59)
#[1] -47

고마워 나는 이것이 훨씬 더 나은 대답이라고 생각합니다. 그것은 많은 요점들을 잘 보여줍니다. 나에게 여전히 조금 불분명 한 유일한 것은-그 자체로 수정 자 (예 : * 9 등)를 생각해 낼 수 있습니까? 그리고 만약 그렇다면 ...
Karolis Koncevičius

이 수정자는 통계의 유의 수준과 같으며 올바른 비교를 거부하기 위해 선택한 위험에 따라 수행 한 작업 수만큼 증가 할 것입니다.
GKi

3

machine.eps의 정의 : 가장 낮은 값  eps 에 대한이  1+eps 되지 않는다 1

(베이스 (2)와 부동 소수점 표현을 가정 함) 경험칙과 같이
eps범위 1 .. 2 차분 만든다
범위를 2 .. 4 정밀도 인 2*eps
등.

불행히도 여기에는 좋은 경험 법칙이 없습니다. 프로그램의 요구에 따라 결정됩니다.

R에서 우리는 근사 평등을 테스트하는 방식으로 모두 동일합니다. 그래서 당신은 아마 같은 것을 사용할 수 있습니다 (x<y) | all.equal(x,y)

i <- 0.1
 i <- i + 0.05
 i
if(isTRUE(all.equal(i, .15))) { #code was getting sloppy &went to multiple lines
    cat("i equals 0.15\n") 
} else {
    cat("i does not equal 0.15\n")
}
#i equals 0.15

구글 모의은 다수가 포인트 매처 (matcher)를 부동 , 배정 밀도의 비교를 포함 DoubleEqDoubleNear. 다음과 같이 배열 매처에서 사용할 수 있습니다.

ASSERT_THAT(vec, ElementsAre(DoubleEq(0.1), DoubleEq(0.2)));

최신 정보:

수치 레시피는 단차 차이 몫을 사용 sqrt하는 것이 미분의 유한 차분 근사에 대해 단계 크기를 선택하는 것이 좋습니다.

Wikipedia 기사 사이트 Numerical Recipes, 3 판, 섹션 5.7, 페이지 229-230 (제한된 페이지보기 수는 http://www.nrbook.com/empanel/ 에서 볼 수 있습니다 ).

all.equal(target, current,
           tolerance = .Machine$double.eps ^ 0.5, scale = NULL,
           ..., check.attributes = TRUE)

이러한 IEEE 부동 소수점 산술 은 컴퓨터 산술의 잘 알려진 제한 사항이며 여러 곳에서 논의됩니다.

. dplyr::near()부동 소수점 숫자의 두 벡터가 같은지 테스트하는 또 다른 옵션입니다.

이 기능에는 공차 매개 변수가 내장되어 tol = .Machine$double.eps^0.5있으며 조정할 수 있습니다. 기본 매개 변수는의 기본값과 동일합니다 all.equal().


2
답변 주셔서 감사합니다. 현재 나는 이것이 최소한의 대답으로 받아 들일 수 없다고 생각합니다. 게시물에서 두 가지 주요 질문을 다루지 않는 것 같습니다. 예를 들어 "프로그램 요구에 따라 결정됩니다"라고 표시됩니다. 이 문장의 한두 가지 예를 보여주는 것이 좋을 것입니다. 아마도 작은 프로그램 일 수도 있고 어떻게 허용 오차를 결정할 수 있을까요? 언급 된 R 스크립트 중 하나를 사용했을 수 있습니다. 또한 all.equal()기본 공차가 있다는 가정 sqrt(double.eps)이 있습니다. 왜 이것이 기본 공차 입니까? 사용하기 좋은 경험 법 sqrt()입니까?
Karolis Koncevičius

다음은 R이 eps를 계산하는 데 사용하는 코드입니다 (자체 프로그램으로 추출). 또한 이전에 겪었던 수많은 토론 포인트로 답변을 업데이트했습니다. 같은 것이 당신이 더 잘 이해하는 데 도움이되기를 바랍니다.
Sreeram Nair

모든 노력에 진심으로 +1. 그러나 현재 상태에서 나는 여전히 대답을 받아 들일 수 없습니다. 많은 참고 문헌으로 조금 벗어나는 것처럼 보이지만 2 개의 게시 된 질문에 대한 실제 답변 측면에서 1) R stats::소스의 100x, 50x 등 수정자를 이해하는 방법 및 2) 지침은 무엇입니까? 답은 매우 얇다. 유일하게 적용 가능한 문장은 sqrt ()가 좋은 기본값 인 "Numerical Recipes"의 참조 인 것 같습니다. 아니면 여기에 뭔가 빠졌을 수도 있습니다.
Karolis Koncevičius
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.