얻은 차이가 기계 정밀도보다 높은지 확인 해야하는 상황이 종종 발생합니다. 이 목적을 위해 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]))
기타
질문
- 어떻게 그 다른 모든 뒤에 추론 이해할 수있는
10 *
,100 *
,50 *
및sqrt()
수정을? .Machine$double.eps
정밀도 문제로 인한 차이 조정 에 대한 지침이 있습니까?
답변
기계 정밀도 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
답변
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 부동 소수점 산술 은 컴퓨터 산술의 잘 알려진 제한 사항이며 여러 곳에서 논의됩니다.
- R의 FAQ에는 다음과 같은 질문이 있습니다. R FAQ 7.31
- 패트릭 번즈 (Patrick Burns)의 R 인페르노 (R Inferno)는 이 문제에 대한 최초의 “원”(9 페이지)
- 수학 메타에서 산술 합계 증명 문제
- 데이비드 골드버그, “무슨 모든 컴퓨터 과학자한다 알고는 부동 소수점 연산에 대해,” ACM 컴퓨팅 설문 조사 (23) , 1 (1991-03), 5-48은 도이> 10.1145 / 103162.103163 ( 도 수정 가능 )
- 부동 소수점 안내서-모든 프로그래머가 부동 소수점 산술에 대해 알아야 할 사항
- 0.30000000000000004.com 은 프로그래밍 언어에서 부동 소수점 산술 비교
- “부동 소수점이 정확하지 않음 “에 대한 정식 복제본 (이 문제에 대한 정식 답변에 대한 메타 토론)
- 다음을 포함한 몇 가지 스택 오버플로 질문
- Arthur T. Benjamin이 설명하는 수학 요령
.
dplyr::near()
부동 소수점 숫자의 두 벡터가 같은지 테스트하는 또 다른 옵션입니다.
이 기능에는 공차 매개 변수가 내장되어 tol = .Machine$double.eps^0.5
있으며 조정할 수 있습니다. 기본 매개 변수는의 기본값과 동일합니다 all.equal()
.