差がマシンの精度よりも小さいかどうかを確認する正しい/標準的な方法は何ですか?


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))

統合します。

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でこの投稿を確認できます。「あは!数値自体が2桁の場合、機械の精度は100倍にもなります」(ピーターダルガード、Rコアチームのメンバー)
Henrik

1
@KarolisKoncevičius、それはそんなに簡単なことではないと思います。これは、浮動小数点演算に存在する一般的なエラーと、それらに対して実行する演算の数に関係しています。単に浮動小数点数と比較する場合は、を使用しますdouble.eps。浮動小数点数に対していくつかの演算を実行している場合は、エラー許容値も調整する必要があります。これがall.equalがあなたにtolerance議論を与える理由です。
ジョセフウッド

1
Rでのnextafter機能の実装を見 て、次に大きなdouble数が得られることも確認してください。
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など)を思い付くことができるかどうかです。そして、もしそうなら...
KarolisKoncevičiusJan

この修飾子は統計の有意水準のようなものであり、正しい比較を拒否するために選択したリスクによって組み合わせて実行した操作の数が増えると思います。
GKi

3

machine.epsの定義:それは最も低い値である  eps ためには  1+eps されていません 1

経験則として(基数2の浮動小数点表現を想定):
これepsにより、範囲1 .. 2と
範囲2 .. 4で精度が異なります2*eps

残念ながら、ここには良い経験則はありません。プログラムのニーズによって完全に決定されます。

Rでは、おおよその同等性をテストするための組み込みの方法としてall.equalがあります。だからあなたはおそらくのようなものを使うことができます(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

Googleモックには、およびを含む、倍精度比較用の多数の浮動小数点マッチャーDoubleEqありDoubleNearます。次のように配列マッチャーで使用できます。

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

更新:

数値レシピは、片側差分商を使用することが、微分のsqrt有限差分近似のステップサイズの適切な選択であることを示すための派生を提供します。

ウィキペディアの記事サイト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()は、浮動小数点数の2つのベクトルが等しいかどうかをテストする別のオプションです。

この関数には、許容誤差パラメーターが組み込まれており、tol = .Machine$double.eps^0.5調整できます。デフォルトのパラメータは、のデフォルトと同じですall.equal()


2
ご回答ありがとうございます。現時点では、これは最小限にすぎず、受け入れられる答えにはならないと思います。投稿からの2つの主要な質問に対応していないようです。たとえば、「プログラムのニーズによって決定される」と述べています。このステートメントの1つまたは2つの例を示すとよいでしょう。おそらく小さなプログラムで、それによって許容範囲をどのように決定できるかです。おそらく、前述のRスクリプトのいずれかを使用しています。またall.equal()、デフォルトの許容値として独自の仮定がありますsqrt(double.eps)-なぜそれがデフォルトなのですか?経験則は良いsqrt()ですか?
KarolisKoncevičius19年

以下は、Rがepsを計算するために使用するコードです(独自のプログラムに抽出されます)。また、私は以前に経験した数多くの議論のポイントで回答を更新しました。同じことがあなたがよりよく理解するのに役立つことを願っています。
Sreeram Nair

すべての努力に対して誠実な+1。しかし、現状ではまだ答えを受け入れることができません。多くの参照で少し範囲を広げているようですが、投稿された2つの質問に対する実際の回答に関しては、1)R stats::ソースの100x、50xなどの修飾子を理解する方法、および2)ガイドラインは何ですか。答えはかなり薄いです。唯一の適用可能な文は、sqrt()が適切なデフォルトであることについての「数値レシピ」からの参照であるようです。または、ここで何か不足しています。
KarolisKoncevičius19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.