Another idea to avoid looking for length(x) * length(ref) :
ff = function(x, ref, tol = 1e-10) { sref = sort(ref) i = findInterval(x, sref, all.inside = TRUE) dif1 = abs(x - sref[i]) dif2 = abs(x - sref[i + 1]) dif = dif1 > dif2 dif1[dif] = dif2[dif] dif1 <= tol } ff(c(1.0, 1+1e-13, 1.01, 2, 2+1e-9, 2-1e-11), c(1, 2, 3)) #[1] TRUE TRUE FALSE TRUE FALSE TRUE
And compare:
set.seed(911) X = sample(1e2, 5e5, TRUE) + (sample(c(1e-8, 1e-9, 1e-10, 1e-12, 1e-13), 5e5, TRUE) * sample(c(-1, 1), 5e5, TRUE)) REF = as.double(1:1e2) all.equal(ff(X, REF), select_in(X, REF))
Frank match should be faster than findInterval , and indeed, with a lot of time spent in round .
source share