The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

06 - Rolling Functions

1 Notes

2 Cumulative sum

Base R provides the cumsum() function to compute the cumulative sum of a vector:

cumsum(1:5)
> cumsum(1:5)
[1]  1  3  6 10 15

One possible C++ function to implement this is:

[[cpp4r::register]]
doubles cumsum_cpp(doubles x) {
  int n = x.size();
  writable::doubles out(n);

  out[0] = x[0];
  for (int i = 1; i < n; ++i) {
    out[i] = out[i - 1] + x[i];
  }
  return out;
}

Its R equivalent would be:

cumsum_r <- function(x) {
  n <- length(x)
  out <- numeric(n)
  out[1] <- x[1]
  for (i in 2:n) {
    out[i] <- out[i - 1] + x[i]
  }
  out
}

Add and document the functions, update the package as in the previous vignettes, and then compare the functions speed with:

# install.packages("microbenchmark")
library(microbenchmark)
library(mypkg)

set.seed(123) # for reproducibility
x <- rpois(1e6, lambda = 2) # 1,000,000 elements
x <- as.numeric(x) # integer to numeric, cumsum_cpp does not accept integers

cumsum(x[1:3])
cumsum_cpp(x[1:3])
cumsum_r(x[1:3])

microbenchmark(
  cumsum(x),
  cumsum_cpp(x),
  cumsum_r(x)
)
Unit: milliseconds
          expr   min    lq   mean median     uq    max neval cld
     cumsum(x)  2.07  2.40   3.40   2.61   4.59   7.04   100  a 
 cumsum_cpp(x)  2.35  2.62   3.84   2.85   4.93  11.00   100  a 
   cumsum_r(x) 91.20 98.50 114.00 109.00 124.00 233.00   100  b

3 Cumulative product

Base R provides the cumprod() function to compute the cumulative product of a vector:

cumprod(1:5)
> cumprod(1:5)
[1]   1   2   6  24 120

One possible C++ function to implement this is:

[[cpp4r::register]] doubles cumprod_cpp(doubles x) {
  int n = x.size();
  writable::doubles out(n);

  out[0] = x[0];
  for (int i = 1; i < n; ++i) {
    out[i] = out[i - 1] * x[i];
  }
  return out;
}

Its R equivalent would be:

cumprod_r <- function(x) {
  n <- length(x)
  out <- numeric(n)
  out[1] <- x[1]
  for (i in 2:n) {
    out[i] <- out[i - 1] * x[i]
  }
  out
}

To test the functions, you can run the following benchmark code in the R console:

microbenchmark(
  cumprod(x),
  cumprod_cpp(x),
  cumprod_r(x)
)
Unit: milliseconds
           expr   min    lq  mean median    uq    max neval cld
     cumprod(x)  2.50  2.66  3.19   2.79  3.04   6.08   100  a 
 cumprod_cpp(x)  2.24  2.45  2.88   2.55  2.71   6.99   100  a 
   cumprod_r(x) 79.70 83.30 93.70  93.50 99.60 125.00   100  b

4 Range of values

A simple example of the range() function in R is:

range(x)
> range(x)
[1]  0 13

One possible C++ function to implement this is:

[[cpp4r::register]]
doubles range_cpp(doubles x) {
  int n = x.size();
  double x1 = x[0], x2 = x[0];

  for (int i = 1; i < n; ++i) {
    x1 = std::min(x1, x[i]);
    x2 = std::max(x2, x[i]);
  }

  writable::doubles out(2);
  out[0] = x1;
  out[1] = x2;

  return out;
}

Write its R equivalent.

To verify the functions, you can run the following tests and benchmark code in the R console:

set.seed(123) # for reproducibility
x <- rnorm(10)

range(x)
range_cpp(x)

bigx <- list(
  rpois(2e6, lambda = 2),
  rpois(4e6, lambda = 2),
  rpois(8e6, lambda = 2)
)

bigx <- lapply(bigx, as.double)

lapply(
  bigx,
  function(x) {
    m <- summary(microbenchmark(range(x), range_cpp(x)))

    data.frame(
      expr = m[, 1], nobs = length(x), median = signif(m[, 5], 3),
      unit = attr(m, "unit")
    )
  }
)
[[1]]
          expr    nobs median         unit
1     range(x) 2000000  17.70 milliseconds
2 range_cpp(x) 2000000   5.42 milliseconds

[[2]]
          expr    nobs median         unit
1     range(x) 4000000   36.1 milliseconds
2 range_cpp(x) 4000000   11.0 milliseconds

[[3]]
          expr    nobs median         unit
1     range(x) 8000000   76.9 milliseconds
2 range_cpp(x) 8000000   22.0 milliseconds

5 References

Vaughan D, Hester J, Francois R (2024). “Get started with cpp11.” https://cpp11.r-lib.org/articles/cpp11.html#intro.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.