4

Assuming I want test if 'a' is less or equal than 'b' when both are floats. I would go with

isTRUE(all.equal(a,b)) || a <= b

I'm wondering if there's a better way than this. Is there a function like all.equal for less or equal ( / greater than equal ) that allows "near equality"?

And what should one do if instead of single numbers one wants to compare two vectors of floats?

Update: @shadow pointed to me Numeric comparison difficulty in R

One could of course set tolerance explicitly and avoid all.equal:

tol = 1e-5

# a equals b
abs(a-b) <= tol

# a less or equal to b
a <= b + tol

Here is some discussion about absolute vs. relative tolerance: http://realtimecollisiondetection.net/blog/?p=89

I guess as always, there's no 'right' way to implement this.

Community
  • 1
  • 1
Ashcroft
  • 100
  • 5
  • R doesn't really document floats. Do you mean doubles? From `?double`, *It is a historical anomaly that R has two names for its floating-point vectors, double and numeric (and formerly had real).* R's numeric types are integer and double. – Rich Scriven Aug 06 '14 at 07:59
  • Sorry, I meant double. – Ashcroft Aug 06 '14 at 08:04
  • At least in c++ it is forbidden to compare the equality of doubles! – user1436187 Aug 06 '14 at 08:23
  • 1
    possible duplicate of [Numeric comparison difficulty in R](http://stackoverflow.com/questions/2769510/numeric-comparison-difficulty-in-r) – shadow Aug 06 '14 at 09:06
  • If you use round(var,digits) with required number of digits, then all your comparisons should be satisfactory with == or <= or >= signs. – rnso Aug 06 '14 at 09:09

1 Answers1

3

Interesting question. I am sure there are better ways, but this simple function takes two vectors of doubles and returns if they are nearly equal element-wise (mode = "ae"), given the specified tolerance. It also can return if they are less than (mode = "lt") or if they are nearly equal or less than (mode = "ne.lt"), along with their "gt" equivalents...

near_equal <- function( x , y , tol = 1.5e-8 , mode = "ae" ){
    ae <- mapply( function(x,y) isTRUE( all.equal( x , y , tolerance = tol ) ) , x , y )    
    gt <- x > y
    lt <- x < y
    if( mode == "ae" )
      return( ae )
    if( mode == "gt" )
      return( gt )
    if( mode == "lt" )
      return( lt )
    if( mode == "ne.gt" )
      return( ae | gt )
    if( mode == "ne.lt" )
      return( ae | lt )
}


#  And in action....
set.seed(1)
x <- 1:5
# [1] 1 2 3 4 5
y <- 1:5 + rnorm(5,sd=0.1)
# [1] 0.9373546 2.0183643 2.9164371 4.1595281 5.0329508


near_equal( x , y , tol = 0.05 , mode = "ae" )
#[1] FALSE  TRUE  TRUE  TRUE  TRUE

near_equal( x , y , tol = 0.05 , mode = "ne.gt" )
#[1] TRUE TRUE TRUE TRUE TRUE

Hope that helps.

Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
  • helps a lot, thanks! Still wondering if there's a built-in solution for this though. Seems to me that there should be one, given the fact that I have encountered this issue multiple times. – Ashcroft Aug 06 '14 at 08:32
  • @Ashcroft not that I am aware of, but don't take that to mean there isn't! I can only remember about 10% of base functions at any given time. – Simon O'Hanlon Aug 06 '14 at 08:37
  • hmm, you might be right. Couldn't find anything built-in – Ashcroft Aug 06 '14 at 11:40