The problem is that when j = ncol - 1
, trying to access x(i, j+1)
in the line
total += x(i, j+1);
is the same as trying to access x(i, ncol)
, and you are out of bounds. If I understand your problem correctly, you can just change j+1
to j
, assuming y
is passed correctly. So, we could change your code to the following:
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::NumericVector PVCalc_cpp(const Rcpp::NumericMatrix& x, int y) {
int nrow = x.nrow(), ncol = x.ncol();
Rcpp::NumericVector out(nrow);
double total = 0;
for (int i = 0; i < nrow; i++) {
total = 0;
for (int j = y; j < ncol; j++){
total += x(i, j);
}
/* The following will always be equal to total but rounded;
to type less R code for the R comparison,
I omit the rounding here.
Notice also the use of [] access operator instead of ();
this is more efficient.
*/
// out[i] = floor((100. * total)+.5)/100;
out[i] = total;
}
return out;
}
We can then verify that this both works, and is faster than rowSums()
:
## Load required packages
library(Rcpp)
library(microbenchmark)
## Source C++ code
sourceCpp("so.cpp")
## Generate example data
x <- matrix(1:9, nrow = 3)
x
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
## Check results are the same
rowSums(x[ , -1])
[1] 11 13 15
PVCalc_cpp(x, 1)
[1] 11 13 15
## Benchmark small example
library(microbenchmark)
microbenchmark(base = rowSums(x[ , -1]),
rcpp = PVCalc_cpp(x, 1))
Unit: microseconds
expr min lq mean median uq max neval
base 5.591 5.9210 8.61073 6.475 6.786 137.125 100
rcpp 2.337 2.5795 19.90118 3.035 3.222 1651.094 100
## Check larger example
set.seed(123)
x <- matrix(rnorm(1e6), nrow = 1e3)
y <- sample(seq_len(ncol(x)), size = 1)
all.equal(rowSums(x[ , -(1:y)]), PVCalc_cpp(x, y))
[1] TRUE
microbenchmark(base = rowSums(x[ , -(1:y)]),
rcpp = PVCalc_cpp(x, y))
Unit: milliseconds
expr min lq mean median uq max neval
base 5.377342 6.052347 6.954338 6.482907 7.834190 11.580706 100
rcpp 1.447596 1.909504 2.085185 2.023343 2.158256 3.159366 100