Skip to content

Instantly share code, notes, and snippets.

@krlmlr
Created December 20, 2012 11:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krlmlr/4344844 to your computer and use it in GitHub Desktop.
Save krlmlr/4344844 to your computer and use it in GitHub Desktop.
library( compiler )
library( microbenchmark )
library( inline )
in.interval1 <- function(x, lo, hi) (x > lo & x < hi)
in.interval2 <- cmpfun( in.interval1 )
in.interval3 <- function(x, lo, hi) findInterval(x, c(lo, hi)) == 1
in.interval4 <- function(x, lo, hi) !is.na(.bincode(x, c(lo, hi)))
in.interval5 <- rcpp( signature(x="numeric", lo="numeric", hi="numeric"), '
NumericVector xx(x);
double lower = Rcpp::as<double>(lo);
double upper = Rcpp::as<double>(hi);
LogicalVector res(xx);
for( int i=0; i < res.size(); i++ ) {
res[i] = (xx[i] > lower) & (xx[i] < upper);
}
return Rcpp::wrap( res );
')
in.interval6 <- rcpp( signature(x="numeric", lo="numeric", hi="numeric"), '
NumericVector xx(x);
double lower = Rcpp::as<double>(lo);
double upper = Rcpp::as<double>(hi);
LogicalVector res(xx);
for( int i=0; i < res.size(); i++ ) {
res[i] = xx[i] > lower && xx[i] < upper;
}
return Rcpp::wrap( res );
')
in.interval7 <- function(x, lo, hi) abs(x-(hi+lo)/2)-(hi-lo)/2 < 0
in.interval8 <- rcpp( signature(x="numeric", lo="numeric", hi="numeric"), '
NumericVector xx(x);
double lower = Rcpp::as<double>(lo);
double upper = Rcpp::as<double>(hi);
double sub1 = (upper + lower) / 2.0;
double sub2 = (upper - lower) / 2.0;
LogicalVector res(xx);
for( int i=0; i < res.size(); i++ ) {
res[i] = fabs(xx[i] - sub1) < sub2;
}
return Rcpp::wrap( res );
')
TESTSAMPLESIZE <- 1e3
x <- runif(TESTSAMPLESIZE)
lo <- 0
hi <- 0.5
b <- in.interval1(x, lo, hi)
stopifnot(any(b))
stopifnot(any(!b))
stopifnot(identical(b, in.interval2(x, lo, hi)))
stopifnot(identical(b, in.interval3(x, lo, hi)))
stopifnot(identical(b, in.interval4(x, lo, hi)))
stopifnot(identical(b, in.interval5(x, lo, hi)))
stopifnot(identical(b, in.interval6(x, lo, hi)))
stopifnot(identical(b, in.interval7(x, lo, hi)))
stopifnot(identical(b, in.interval8(x, lo, hi)))
SAMPLESIZE <- 1e6
x <- runif(SAMPLESIZE)
lo <- 0
hi <- 0.5
microbenchmark(
in.interval1(x, lo, hi),
in.interval2(x, lo, hi),
in.interval3(x, lo, hi),
in.interval4(x, lo, hi),
in.interval5(x, lo, hi),
in.interval6(x, lo, hi),
in.interval7(x, lo, hi),
in.interval8(x, lo, hi),
times=3
)
x <- rnorm(SAMPLESIZE)
lo <- -0.5
hi <- 0.5
microbenchmark(
in.interval1(x, lo, hi),
in.interval2(x, lo, hi),
in.interval3(x, lo, hi),
in.interval4(x, lo, hi),
in.interval5(x, lo, hi),
in.interval6(x, lo, hi),
in.interval7(x, lo, hi),
in.interval8(x, lo, hi),
times=3
)
all: results.log
results.log: benchmark.R Makefile
r -p benchmark.R | tee results.log
Unit: milliseconds
expr min lq median uq max
1 in.interval1(x, lo, hi) 37.17666 38.42437 39.67208 41.09402 42.51595
2 in.interval2(x, lo, hi) 37.40908 37.40916 37.40923 60.05991 82.71058
3 in.interval3(x, lo, hi) 38.50727 39.60490 40.70253 67.27891 93.85530
4 in.interval4(x, lo, hi) 19.78177 21.85969 23.93762 25.05246 26.16730
5 in.interval5(x, lo, hi) 15.18608 15.73077 16.27546 41.53891 66.80235
6 in.interval6(x, lo, hi) 15.22456 16.31206 17.39956 40.49614 63.59272
7 in.interval7(x, lo, hi) 27.82003 50.75206 73.68408 98.93059 124.17711
8 in.interval8(x, lo, hi) 16.28154 16.30808 16.33462 16.34517 16.35571
Unit: milliseconds
expr min lq median uq max
1 in.interval1(x, lo, hi) 38.98638 39.66520 40.34402 40.75315 41.16228
2 in.interval2(x, lo, hi) 42.10256 42.23833 42.37410 42.92669 43.47928
3 in.interval3(x, lo, hi) 45.34348 46.88152 48.41956 70.01567 91.61178
4 in.interval4(x, lo, hi) 19.60766 21.77997 23.95228 24.57502 25.19776
5 in.interval5(x, lo, hi) 15.21367 15.24321 15.27276 15.78392 16.29508
6 in.interval6(x, lo, hi) 19.13099 19.15701 19.18302 21.32998 23.47694
7 in.interval7(x, lo, hi) 32.75138 33.10463 33.45789 34.24936 35.04084
8 in.interval8(x, lo, hi) 15.16925 15.74474 16.32023 16.86394 17.40766
@kevinushey
Copy link

Try:

LogicalVector res(xx);
for( int i=0; i < res.size(); i++ ) {
  res[i] = xx[i] > lower & xx[i] < upper;
}
return Rcpp::wrap( res );

instead of the return call at the end (as well as the un-necessary assignment of res I had before)

@mtmorgan
Copy link

in line 8 compare to integer 1L; do a better job of replication e.g., times=100

@mtmorgan
Copy link

This is a C implementation, without checks on type or length of arguments. Also, in.interval7 can be optimized by moving (hi - lo) /2 to the other side of the inequality.

in.interval_c <- cfunction(c(x="numeric", lo="numeric", hi="numeric"),
'    int len = Rf_length(x);
     double lower = REAL(lo)[0], upper = REAL(hi)[0],
            *xp = REAL(x);
     SEXP out = PROTECT(NEW_LOGICAL(len));
     int *outp = LOGICAL(out);
     for (int i = 0; i < len; ++i)
         outp[i] = (xp[i] - lower) * (xp[i] - upper) <= 0;
     UNPROTECT(1);
     return out;')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment