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


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.equal 이 tolerance인수를 제공하는 이유 입니다.
— 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변경되지 않습니다 b때 a입니다 <= 그것의 기계 정밀도의 절반. 차이가 기계 정밀도보다 작은 지 확인하십시오 <. 수정자는 추가가 변경을 표시하지 않은 일반적인 경우를 고려할 수 있습니다.

에서 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)를 부동 , 배정 밀도의 비교를 포함 DoubleEq와 DoubleNear. 다음과 같이 배열 매처에서 사용할 수 있습니다.

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.