Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 检查差值是否小于机器精度的正确/标准方法是什么?_R_Floating Point_Rounding_Precision - Fatal编程技术网

R 检查差值是否小于机器精度的正确/标准方法是什么?

R 检查差值是否小于机器精度的正确/标准方法是什么?,r,floating-point,rounding,precision,R,Floating Point,Rounding,Precision,我经常在需要检查获得的差异是否高于机器精度的情况下结束。似乎为此R有一个方便的变量:.Machine$double.eps。然而,当我在R源代码中找到关于使用这个值的指南时,我看到了多种不同的模式 例子 以下是stats库中的几个示例: t、 测试R 整合 rel.tol

我经常在需要检查获得的差异是否高于机器精度的情况下结束。似乎为此R有一个方便的变量:
.Machine$double.eps
。然而,当我在R源代码中找到关于使用这个值的指南时,我看到了多种不同的模式

例子 以下是
stats
库中的几个示例:

t、 测试R

整合

rel.tol
lm.影响.R


e[abs(e)<100*.Machine$double.eps*中位数(abs(e))]机器的定义。eps:它是
eps
的最低值,其中
1+eps
不是
1

根据经验(假设以2为底的浮点表示法):
eps
对范围1产生差异。。2,
范围为2。。4精度为
2*eps

等等

不幸的是,这里没有好的经验法则。这完全取决于你课程的需要


在R中,我们使用all.equal作为测试近似相等性的内置方法。因此,您可以使用类似于
(x的东西
double
的机器精度取决于其当前值。
机器$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
每个
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
如果可以将其转换为整数,则可以使用gmp(Rmpfr中的内容)


相关:因此,两篇文章都认为“合理的确定程度”取决于你的应用。作为一个案例研究,你可以检查:“啊哈!当数字本身是两位数时,100倍的机器精度并不是那么高。”@KarolisKoncevičius,我不认为这有那么简单。这与浮点数学中存在的一般错误以及对它们执行的操作数有关。如果只是与浮点数进行比较,请使用
double.eps
。如果对一个浮点数执行多个操作,那么您的容错能力会下降你也需要调整。这就是为什么给你一个
容差
参数的原因。同时看看什么会给你下一个更大的双倍数字。感谢你的回答。目前我认为这太小了,不能成为一个可接受的答案。它似乎没有解决帖子中的两个主要问题。例如,它指出“它是由你的程序的需求决定的”。最好能展示一个或两个这样的例子——可能是一个小程序,以及它是如何决定公差的。可能使用上面提到的一个R脚本。另外
all.equal()
有自己的假设作为默认公差存在
sqrt(double.eps)
-为什么是默认值?使用
sqrt()
是否是一个好的经验法则?这里是(提取到自己的程序中)。此外,我已经更新了我之前讨论过的许多问题的答案。希望这有助于你更好地理解。真诚的+1感谢你的所有努力。但在目前的状态下,我仍然无法接受答案。参考文献很多,似乎有点牵强,但就发布的两个问题的实际答案而言:1)如何理解R
stats::
source中的100x、50x等修饰符,以及2)指导原则是什么;答案很简单。唯一适用的句子似乎是关于sqrt()的“数字配方”参考作为一个很好的默认值,这是非常重要的,我觉得。或者我在这里遗漏了一些东西。非常感谢。我觉得这是一个更好的答案。它很好地说明了很多要点。唯一对我来说仍然有点不清楚的是——是否可以提出修饰符(如*9等)他/她自己?如果是这样的话,如何…我认为这个修饰符类似于统计学中的显著性水平,并且会随着您所做的操作数量的增加,再加上所选择的风险,以拒绝正确的比较。
rel.tol < max(50*.Machine$double.eps, 0.5e-28)
e[abs(e) < 100 * .Machine$double.eps * median(abs(e))] <- 0
if (any(ev[neg] < - 9 * .Machine$double.eps * ev[1L]))
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
ASSERT_THAT(vec, ElementsAre(DoubleEq(0.1), DoubleEq(0.2)));
all.equal(target, current,
           tolerance = .Machine$double.eps ^ 0.5, scale = NULL,
           ..., check.attributes = TRUE)
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
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
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
library(Rmpfr)
mpfr("2", 1024L)^54 - 2.9 + 4.1 - (mpfr("2", 1024L)^54 + 5.9)
#[1] -4.700000000000000621724893790087662637233734130859375
library(gmp)
as.bigz("2")^54 * 10 - 29 + 41 - (as.bigz("2")^54 * 10 + 59)
#[1] -47