2

I have a vector with variable elements in it, and I want to check whether it's last two element are in the same digit order.

For example, if the last two vectors are 0.0194 and 0.0198 return TRUE. because their digit order after zero is the same (0.01 order 10^-2). ! for other example the number could be 0.00014 and 0.00012 so their precision is still around the same the function should return also TRUE.

How can we build a logical statement or function to check this.

x<- c(0.817104, 0.241665, 0.040581, 0.022903, 0.019478, 0.019846)
Alexander
  • 4,527
  • 5
  • 51
  • 98
  • @rawr ok I edited. – Alexander Apr 12 '16 at 02:21
  • you mean you want to see if the first non zero digit in both are ordered assuming they have the same place value? so `c(0.019, 0.011)` is true and `c(0.01, 0.001)` is false? – rawr Apr 12 '16 at 02:28

2 Answers2

4

I may be over-thinking this, but you can test that the order of magnitude and first non-zero digit are identical for each.

x <- c(0.817104, 0.241665, 0.040581, 0.022903, 0.019478, 0.019846)

oom <- function(x, base = 10) as.integer(ifelse(x == 0, 0, floor(log(abs(x), base))))
oom(x)
# [1] -1 -1 -2 -2 -2 -2

(tr <- trunc(x / 10 ** oom(x, 10)))
# [1] 8 2 4 2 1 1

So for the last two, the order of magnitude for both is -2 and the first non-zero digit is 1 for both.

Put into a function:

f <- function(x) {
  oom <- function(x, base = 10) as.integer(ifelse(x == 0, 0, floor(log(abs(x), base))))
  x <- tail(x, 2)
  oo <- oom(x)
  tr <- trunc(x / 10 ** oo)
  (oo[1] == oo[2]) & (tr[1] == tr[2])
}

## more test cases
x1 <- c(0.019, 0.011)
x2 <- c(0.01, 0.001)

f(x)  ## TRUE
f(x1) ## TRUE
f(x2) ## FALSE

Here is a more general function than the above for checking the last n instead of 2

g <- function(x, n = 2) {
  oom <- function(x, base = 10) as.integer(ifelse(x == 0, 0, floor(log(abs(x), base))))
  x <- tail(x, n)
  oo <- oom(x)
  tr <- trunc(x / 10 ** oo)
  Reduce(`==`, oo) & Reduce(`==`, tr)
}

g(c(.24, .15, .14), 2)  ## TRUE
g(c(.24, .15, .14), 3)  ## FALSE
rawr
  • 20,481
  • 4
  • 44
  • 78
2

@rawr worries about over-thinking. I guess I should as well. This is what I came up with and do note that this handles the fact that print representations of floating point numbers are sometimes deceiving.

orddig <- function(x) which( sapply( 0:16, function(n){ isTRUE(all.equal(x*10^n ,  
                                                                   round(x*10^n,0)))}))[1]
> sapply( c(0.00014 , 0.00012 ), orddig)
[1] 6 6

My original efforts were with the signif function but that's a different numerical thought trajectory, since 0.01 and 0.001 have the same number of significant digits. Also notice that:

> sapply( 10^5*c(0.00014 , 0.00012 ), trunc, 4)
[1] 13 12

Which was why we need the isTRUE(all.equal(... , ...))

IRTFM
  • 258,963
  • 21
  • 364
  • 487