Skip to content

Instantly share code, notes, and snippets.

@strboul
Last active October 14, 2019 14:22
Show Gist options
  • Save strboul/97cf7456e7a4e8c51fada5d9e298b819 to your computer and use it in GitHub Desktop.
Save strboul/97cf7456e7a4e8c51fada5d9e298b819 to your computer and use it in GitHub Desktop.
Calculating the average of two integer numbers (decimal results are rounded down towards zero) in R
inline::cfunction(c(asexp = "integer", bsexp = "integer"), '
int a = Rf_asInteger(asexp);
int b = Rf_asInteger(bsexp);
int avg = (a>>1)+(b>>1)+(a&b&1);
SEXP out = PROTECT(allocVector(INTSXP, 1));
out = Rf_ScalarInteger(avg);
UNPROTECT(1);
return out;
') -> avg_two_ints
(INT_1 <- sample(seq(1e3, 1e5), 1L))
(INT_2 <- sample(seq(1e3, 1e5), 1L))
microbenchmark::microbenchmark(
avg_two_ints(INT_1, INT_2), ## bitwise
floor((INT_1 + INT_2) / 2L), ## binary operators
floor(mean(c(INT_1, INT_2))), ## floor - mean
check = "identical"
)
## Using binary operators in R is the fastest solution in this case. But still
## the bit operation faster than the floor-mean combination which may possible
## be due to that floor-mean calls GC at least two times during its operation.
##
## Sources:
## Calculating the average of two integer numbers rounded towards zero in a
## single instruction cycle
## - https://patents.google.com/patent/US6007232A
## - https://twitter.com/gamepopper/status/1180037076701601793
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment