0

In R, I find it a bit annoying to have to transform easy-to-read code like:

if (det(A) == 1)       # not always working because of floating point precision
    ...

to

if (abs(det(A) - 1) < .Machine$double.eps)     # working but bad for readability
    ...

Question: is there a built-in operator in R that tests if values are equal "up to a .Machine$double.eps error"? Something like:

if (det(A) ==~ 1)       # TRUE even if det(A) = 1 + 1e-17
    ...
Basj
  • 41,386
  • 99
  • 383
  • 673
  • Maybe you are looking for `all.equal`? it has a tolerance argument. – lmo Nov 10 '17 at 10:56
  • @lmo I mean having a short (< 5 characters, e.g. `==~`), easily readable equality test, up to a certain precision (e.g. given by .Machine$double.eps) – Basj Nov 10 '17 at 10:58
  • 1
    You can always construct your own operator if the length is that important to you. I am not aware of such an operator available in base R. – lmo Nov 10 '17 at 11:01
  • 3
    Automatically thinking in terms of double.eps may be a mistake. The allowed deviation from 1 has to be big enough for the maximum total rounding error on the calculation leading to the test. Depending on the calculation and inputs, that may be bigger than double.eps. – Patricia Shanahan Nov 10 '17 at 11:14
  • @PatriciaShanahan can you elaborate on this (possibly post an answer), showing an example why it would be a mistake? – Basj Nov 10 '17 at 11:21
  • 1
    @Basj Have you read [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)? – Patricia Shanahan Nov 10 '17 at 11:31
  • @Basj: Each basic floating-point operations behaves as if it computed the exactly mathematical result of its inputs and then rounded the result to the nearest representable value. This rounded value is then input for further operations, which do the same thing, thus rounding again. So a sequence of floating-point operations as a sequence of rounding errors. Sometimes they happen to cancel. Sometimes they happen to reinforce. And, in the worst cases, they can grow in various ways. To understand the error that can occur in a program, it has to be analyzed individually. – Eric Postpischil Nov 10 '17 at 15:29
  • Even if it is linked to this other answer @EricPostpischil, it is not a duplicate since mine adresses the question of defining a new operator. Also, the question you linked is heavily obscured with some context (seq, which.max, sample, rex, replicate , etc.) which makes it difficult to get the information, and not accessible to a R learner who doesn't know all these specific functions. – Basj Nov 10 '17 at 16:09
  • This question is contained in the other: There cannot be an operator for this operation because no correct general operation for this exists. – Eric Postpischil Nov 10 '17 at 17:06
  • 2
    I suppose you're right, technically this isn't an exact duplicate. However, the way you've phrased this question, it's a rather boring one, since the only correct answer seems to be "no, there isn't". If you were to rephrase it as, say, "is there a built-in operator [that does this] *or can one be easily defined*?", then Rui Barradas' answer below would become valid. – Ilmari Karonen Nov 10 '17 at 21:18

2 Answers2

4

One way would be to declare a function %=~ like this.

`%=~%` <- function(x, y, tol = .Machine$double.eps^0.5) abs(x - y) < tol

2 %=~% (2+1e-15)
#[1] TRUE

You could then use the tolerance tol of your choice.

Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
1

I think what @Patricia is getting at is something like this

xx <- seq(0, 5e4, length.out=3e2)
dif <- Re(fft(fft(xx), inverse=TRUE)/length(xx)) - xx

plot(dif, type="p", pch=16, cex=0.8)
max(abs(dif))
# 4.365575e-11

That's quite a far way off .Machine$double.eps

Nonetheless, an infix operator can be implemented something like this

`%zeq%` <- function(lhs, rhs) {
    isTRUE(all.equal(lhs, rhs, tolerance = 1e-10))
}

2 %zeq% (2+1e-10)

Somewhat co-opting Rob Eastaways 'zequals'.

AkselA
  • 8,153
  • 2
  • 21
  • 34