考虑以下R函数
is.sqrt <- function(x, y){
if(x^2 == y) TRUE
else FALSE
}
它回答x是否是y的平方根。如果y是一个完美的正方形,则函数的行为与预期一致 - is.sqrt(2,4)返回TRUE,is.sqrt(3,4)返回FALSE。如果y不是完美的正方形,则会出现问题。例如,
is.sqrt(sqrt(2), 2)
返回FALSE。通过计算可以看出原因
sqrt(2)^2 - 2
返回4.440892e-16。我对如何解决这个问题的第一个想法是在将它与y进行比较之前对x ^ 2进行舍入但是多少是合适的?这甚至是推荐的方式吗? R中是否有标准方法来处理浮点精度?
答案 0 :(得分:5)
你可以在你的函数中使用all.equal
,“测试两个对象是否'几乎'相等”
is.sqrt <- function(x, y){
isTRUE(all.equal(x^2,y)
}
is.sqrt(sqrt(2), 2)
# TRUE
is.sqrt(sqrt(2), 3)
# FALSE
答案 1 :(得分:1)
您可以使用near
中的dplyr
功能,它具有内置容差。
is.sqrt <- function(x, y) {
near(x^2, y)
}
is.sqrt(sqrt(2), 2)
> TRUE
答案 2 :(得分:0)
另一种选择可能是使用all.equal.numeric
本身。
选项-A)强>
is.sqrt <- function(x, y){
isTRUE(all.equal.numeric(x^2, y))
}
#> is.sqrt(sqrt(2),2)
#[1] TRUE
选项-B)强>
使用公差限制双精度。可以选择使用.Machine.double.eps
但我更喜欢使用固定值1e-8
。
is.sqrt_abs_tol<- function(x, y){
tol <- 1e-8 # OR .Machine$double.eps can be used
abs(x^2 - y) <= tol
}
#> is.sqrt_abs_tol(sqrt(2), 2)
#[1] TRUE
根据 @docendodiscimus 的同意,我想对这些选项进行一些性能分析。
library(microbenchmark)
library(dplyr)
is.sqrt_Dan <- function(x, y){
isTRUE(all.equal(x^2,y))
}
is.sqrt_MKR <- function(x, y){
isTRUE(all.equal.numeric(x^2, y))
}
is.sqrt_Leon <- function(x, y) {
near(x^2, y)
}
is.sqrt_abs_tol<- function(x, y){
tol <- 1e-5
abs(x^2 - y) <= tol
}
microbenchmark(
is.sqrt_Leon(sqrt(2), 2),
is.sqrt_Dan(sqrt(2), 2),
is.sqrt_MKR(sqrt(2), 2),
is.sqrt_abs_tol(sqrt(2), 2),
times=1000L
)
expr min lq mean median uq max neval
is.sqrt_Leon(sqrt(2), 2) 2369 3948 4736.816 4737 5132 60001 1000
is.sqrt_Dan(sqrt(2), 2) 36711 38291 44590.051 39474 41844 2750542 1000
is.sqrt_MKR(sqrt(2), 2) 32369 33949 38130.556 35133 37501 211975 1000
is.sqrt_abs_tol(sqrt(2), 2) 395 1185 4571.833 1579 1580 3107387 1000
上述分析中几乎没有观察到:
near
的{{1}}函数比dplyr
变体更快。all.equal
比all.equal.numeric
all.equal
和abs
的自定义版本超快。