How to deal with floating point errors in R

后端 未结 3 1179
挽巷
挽巷 2021-01-06 13:59

Consider the following R function

is.sqrt <- function(x, y){
  if(x^2 == y) TRUE
  else FALSE
}

which answers whether x is the square ro

相关标签:
3条回答
  • 2021-01-06 14:47

    you can use all.equal in your function, which "tests if two objects are 'nearly' equal"

    is.sqrt <- function(x, y){
        isTRUE(all.equal(x^2,y)
    }
    
    
     is.sqrt(sqrt(2), 2)
     # TRUE
    
     is.sqrt(sqrt(2), 3)
     # FALSE
    
    0 讨论(0)
  • 2021-01-06 14:55

    You can use the near function from dplyr, it has a built-in tolerance.

    is.sqrt <- function(x, y) {
      near(x^2, y)
    }
    
    is.sqrt(sqrt(2), 2)
    
    > TRUE
    
    0 讨论(0)
  • 2021-01-06 14:58

    Another option could be to use all.equal.numeric itself.

    Option-A)

    is.sqrt <- function(x, y){
      isTRUE(all.equal.numeric(x^2, y))
    }
    
    #> is.sqrt(sqrt(2),2)
    #[1] TRUE
    

    Option-B)

    Using tolerance limit double precision. Optionally one can use .Machine.double.eps but I had preferred to use a fixed value as 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
    

    As agreed with @docendodiscimus, I thought do some performance analysis about these options.

    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
    

    Few observations from the analysis above:

    • Surprisingly near function from dplyr is faster than all.equal variants.
    • all.equal.numeric is slightly faster than all.equal
    • The custom version using abs and tolerance is super-fast.
    0 讨论(0)
提交回复
热议问题