0

I have the following matrix

M <- structure(c(0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
0, 0, 1, 0, 0, 0, 1, 0), .Dim = c(5L, 5L))

I want to find the eigenvalues that are exactly 1. I thought this would work:

Re(eigen(M)$values) == 1 & Im(eigen(M)$values) == 0

but Re(eigen(M)$values) == 1 doesn't think the 5th eigenvalues equals 1, even though it does. What am I missing?

EDIT: As soon as it's pointed out as a floating point problem, I investigate a bit more and find out about several solution, including using abs(value) < tol, all.equal, and signif. Could an answer discuss these options?

Heisenberg
  • 8,386
  • 12
  • 53
  • 102
  • 2
    Could be the float issue like [here](http://stackoverflow.com/questions/9508518/why-are-these-numbers-not-equal) – akrun Sep 23 '15 at 03:24
  • 1
    On my computer, `Re(eigen(M)$values)[5]` gives `0.9999999999999997779554` with `options(digits = 22)`. –  Sep 23 '15 at 03:25
  • 1
    Because `format(Re(eigen(M)$values[c(3, 5)]), digits=22) [1] "1.0000000000000000000000" "0.9999999999999997779554"` – Rich Scriven Sep 23 '15 at 03:26
  • 1
    Another way could be `Re(eigen(M)$values) %%1 == 0 & Im(eigen(M)$values) %% 1 == 0`, which give `FALSE FALSE TRUE TRUE FALSE`. –  Sep 23 '15 at 04:43

2 Answers2

5

In R, the usual way to deal with floating-point numbers in the case of comparisons like == is to use the function all.equal().

You may want to try:

sapply(1:nrow(M), function(x) identical(all.equal(eigen(M)$values[x],1+0i),TRUE))
[1] FALSE FALSE  TRUE FALSE  TRUE

There are often workarounds that lead to the same result (round, signif...), but using all.equal() is preferable since it is a function that is designed to handle comparisons of floating point numbers, without the need to tweak accuracy thresholds or to specify the number of significant digits.

As stated in ?Comparison:

For numerical and complex values, remember == and != do not allow for the finite representation of fractions, nor for rounding error. Using all.equal with identical is almost always preferable.

RHertel
  • 23,412
  • 5
  • 38
  • 64
  • Could you explain why this is the preferred way in R? – Heisenberg Sep 23 '15 at 05:50
  • But aren't the results wrong? It should be `FALSE FALSE TRUE TRUE FALSE`. –  Sep 23 '15 at 05:59
  • They look look good to me. According to my computer the fourth eigenvalue is (-1+0i). If that one should be included in the `TRUE` list, too; then one may need to add `abs()` somewhere. – RHertel Sep 23 '15 at 06:02
  • But it is a real. It should be included. But not the fifth, as already showed in the comments. –  Sep 23 '15 at 06:04
  • `Re(eigen(M)$values)` yields `-0.5 -0.5 1.0 -1.0 1.0`. According to the OP one of the conditions is that only the values with a real value equal to 1 should be included, if I understood the question correctly. The third and the fifth value fulfill this condition within the accuracy of floating-point calculations, but the fourth doesn't. – RHertel Sep 23 '15 at 06:14
  • But the real part of the fifth element is not equal to 1. –  Sep 23 '15 at 09:43
  • @Pascal Analytically the fifth eigenvalue is equal to one. The differences you mentioned in the comment are artifacts due to floating-point arithmetics. The corresponding eigenvector is (1/sqrt(3))*(-1,-1,-1,0,0)^T. – RHertel Sep 23 '15 at 11:43
0

You may have to use abs; this has to do w/ float point precision:

abs(Re(eigen(M)$values) - 1) < .001
Chris Watson
  • 1,347
  • 1
  • 9
  • 24