如何处理R中的浮点错误

时间:2018-02-20 13:25:12

标签: r floating-point

考虑以下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中是否有标准方法来处理浮点精度?

3 个答案:

答案 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.equalabs的自定义版本超快