Kar*_*ius 36 floating-point precision r rounding
我经常遇到需要检查获得的差异是否高于机器精度的情况。似乎为此目的,R 有一个方便的变量:.Machine$double.eps. 但是,当我转向 R 源代码以获取有关使用此值的指南时,我看到了多种不同的模式。
以下是stats库中的一些示例:
t.test.R
if(stderr < 10 *.Machine$double.eps * abs(mx))
Run Code Online (Sandbox Code Playgroud)
chisq.test.R
if(abs(sum(p)-1) > sqrt(.Machine$double.eps))
Run Code Online (Sandbox Code Playgroud)
积分
rel.tol < max(50*.Machine$double.eps, 0.5e-28)
Run Code Online (Sandbox Code Playgroud)
影响力
e[abs(e) < 100 * .Machine$double.eps * median(abs(e))] <- 0
Run Code Online (Sandbox Code Playgroud)
原理图
if (any(ev[neg] < - 9 * .Machine$double.eps * ev[1L]))
Run Code Online (Sandbox Code Playgroud)
等等。
10 *,100 *,50 *和sqrt()修饰?.Machine$double.eps用于调整因精度问题而导致的差异的指南?machine.eps的定义:它是最低值\xc2\xa0 eps\xc2\xa0,其中\xc2\xa0 1+eps\xc2\xa0不是\xc2\xa01
根据经验(假设以 2 为基数的浮点表示):
\n这eps会导致范围 1 .. 2 的差异,
\n对于范围 2 .. 4 的精度为2*eps
\n,依此类推。
不幸的是,这里没有好的经验法则。这完全取决于您的程序的需求。
\n\n在 R 中,我们有 all.equal 作为测试近似相等的内置方法。所以你可以使用类似的东西(x<y) | all.equal(x,y)
i <- 0.1\n i <- i + 0.05\n i\nif(isTRUE(all.equal(i, .15))) { #code was getting sloppy &went to multiple lines\n cat("i equals 0.15\\n") \n} else {\n cat("i does not equal 0.15\\n")\n}\n#i equals 0.15\nRun Code Online (Sandbox Code Playgroud)\n\nGoogle mock 有许多用于双精度比较的浮点匹配器,包括DoubleEq和DoubleNear。您可以在数组匹配器中使用它们,如下所示:
ASSERT_THAT(vec, ElementsAre(DoubleEq(0.1), DoubleEq(0.2)));\nRun Code Online (Sandbox Code Playgroud)\n\n更新:
\n\n数值配方提供了一种推导来证明使用单边差商,sqrt是导数有限差分近似的步长的良好选择。
维基百科文章网站 Numerical Recipes,第 3 版,第 5.7 节,第 229-230 页(有限数量的页面浏览量可在http://www.nrbook.com/empanel/上获得)。
\n\nall.equal(target, current,\n tolerance = .Machine$double.eps ^ 0.5, scale = NULL,\n ..., check.attributes = TRUE)\nRun Code Online (Sandbox Code Playgroud)\n\n这些IEEE 浮点运算是计算机运算的众所周知的限制,并在多个地方进行了讨论:
\n\n.\n dplyr::near()是测试两个浮点数向量是否相等的另一个选项。
该函数有一个内置的容差参数:tol = .Machine$double.eps^0.5可以调整。默认参数与 的默认参数相同all.equal()。
机器精度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
Run Code Online (Sandbox Code Playgroud)
增加价值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
Run Code Online (Sandbox Code Playgroud)
每个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
Run Code Online (Sandbox Code Playgroud)
Rmpfr可以使用更高的精度。
library(Rmpfr)
mpfr("2", 1024L)^54 - 2.9 + 4.1 - (mpfr("2", 1024L)^54 + 5.9)
#[1] -4.700000000000000621724893790087662637233734130859375
Run Code Online (Sandbox Code Playgroud)
如果可以将其转换为整数gmp,则可以使用(Rmpfr 中的内容)。
library(gmp)
as.bigz("2")^54 * 10 - 29 + 41 - (as.bigz("2")^54 * 10 + 59)
#[1] -47
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1276 次 |
| 最近记录: |