Skip to content

Instantly share code, notes, and snippets.

@FlukeAndFeather
Last active October 3, 2019 22:13
Show Gist options
  • Save FlukeAndFeather/cc77ed3374b6fb2686e600a9503f4065 to your computer and use it in GitHub Desktop.
Save FlukeAndFeather/cc77ed3374b6fb2686e600a9503f4065 to your computer and use it in GitHub Desktop.
R function for finding zero-crossing values in a vector. In the case of exact zeros, carries the previous sign forward. I.e. [+ + 0 -] has a zero-cross at position 4, but [+ + 0 +] has no zero-crosses.
find0cross <- function(x) {
# x must be numeric
stopifnot(is.numeric(x))
# Length 0 and 1 can't have zero crossings
if (length(x) < 2) {
return(rep(FALSE, length(x)))
}
# Recursively find zero-crossing values
is_cross <- function(y, s) {
if (length(y) == 0) {
return(logical(0))
}
s1 <- sign(y[1])
yn <- y[-1]
if (s1 == 0) {
c(FALSE, is_cross(yn, s))
} else {
c(s1 * s < 0, is_cross(yn, s1))
}
}
# Start looking at the first non-zero value
if (all(x == 0)) {
return(rep(FALSE, length(x)))
}
result <- logical(length(x))
first_non0 <- which(x != 0)[1]
result[1:first_non0] <- FALSE
if (first_non0 == length(x)) {
return(result)
}
s <- sign(x[first_non0])
for (i in (first_non0 + 1):length(x)) {
si <- sign(x[i])
if (si == 0) {
result[i] <- FALSE
} else {
result[i] <- s * si < 0
s <- si
}
}
result
}
x <- c(rep(5, 3), rep(0, 2), rep(-5, 3), 5, 5, 0, 5, -5)
# Should be 6, 9, 13
which(find0cross(x))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment