r语言 - 在C++中使用 RCPP 的 NumericMatrix 循环是否是一个好的理想?
r - Is it a good ideal to use loops for Rcpp's NumericMatrix in C++?
我想使用Rcpp::NumericMatrix
作为C++函数的参数类型,该函数将循环通过它。我现在应该将Rcpp::NumericMatrix
的全部内容复制到C样式数组中以获得良好的性能吗?还是在C++循环中多次使用Rcpp::NumericMatrix
的[]运算符也很快?有没有比使用随机访问来循环通过Rcpp::NumericMatrix
实例更快的方法?
由于这是一个相当悠闲的日子,我无法快速找到这方面的基准(Rcpp Sugar第4节待定,第6节待定)。。。我的好奇心。。。让我们试一试吧!
首先,要访问NumericMatrix
的c样式数组,我们首先需要将NumericMatrix
转换为std::vector
。从std::vector
中,我们可以提取一个由指针控制的c-样式数组。在这种结构下,我们正在完全复制数据。尽管如此,我们可以先调查所提出的问题,然后再调查一些问题。
下面是一套快速测试功能,主要针对四个不同的组件:
- c样式数组
std::accumulate
- 循环
std::vector
- 使用
NumericMatrix
进行元素访问
现在,我在纯c-样式函数中进行了"欺骗",因为我没有尝试通过sizeof()
计算从自身计算数组的大小。(这可能会导致一些问题,因为指针大小会被给定…)
让我们来看看函数的测试套件。
#include <Rcpp.h>
// [[Rcpp::export]]
double c_for_access(const Rcpp::NumericMatrix& x){
// Cast to std vector
std::vector<double> v = Rcpp::as<std::vector<double> >(x);
// Convert to c-style pointer
double* pv = &v[0];
// Sum using a pointer
double sum = 0;
for(unsigned int i = 0; i < v.size(); i++){
sum += *(pv+i);
}
return sum;
}
// [[Rcpp::export]]
double stl_for_access(const Rcpp::NumericMatrix& x){
// Cast to std vector
std::vector<double> v = Rcpp::as<std::vector<double> >(x);
// Summing Operation
double sum = 0;
for(unsigned int i = 0; i < v.size(); i++){
sum += v[i];
}
return sum;
}
// [[Rcpp::export]]
double stl_access(const Rcpp::NumericMatrix& x){
// Cast to STL Vector
std::vector<double> v = Rcpp::as<std::vector<double> >(x);
// Use STL to return sum
return std::accumulate(v.begin(), v.end(), 0.0); // Important to specify 0.0 instead of 0.
}
// [[Rcpp::export]]
double matrix_access(const Rcpp::NumericMatrix& x) {
// Define matrix information and looping variables.
unsigned int r = x.nrow(), c = x.ncol(), i, j;
// Sum elements
double sum = 0;
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
sum += x(i,j);
}
}
return sum;
}
现在,让我们生成一些数据:
# Set seed for reproducibility
set.seed(1337)
# Create a 100x100 matrix
x = matrix(rnorm(10000),nrow=100,ncol=100)
接下来,我们计算并检查每个对象的总和,以确保它们都相等:
# Calculate each object
oracle = sum(x) # Oracle is the correct answer given by R
c.out = c_for_access(x)
stl.loop = stl_for_access(x)
stl.lib = stl_access(x)
rcpp.pure = matrix_access(x)
# Check all equal
all.equal(oracle, c.out)
all.equal(oracle, stl.loop)
all.equal(oracle, stl.lib)
all.equal(oracle, rcpp.pure)
最后,我们在每个函数上运行微基准标记:
# install.packages("microbenchmark")
microbenchmark::microbenchmark(oracle = sum(x),
c.out = c_for_access(x),
stl.loop = stl_for_access(x),
stl.lib = stl_access(x),
rcpp.pure = matrix_access(x)
)
从微基准点来看,我们有:
Unit: microseconds
expr min lq mean median uq max neval
oracle 8.105 8.705 9.11406 8.7060 9.0060 24.016 100
c.out 30.319 31.220 31.75767 31.2210 31.5210 54.636 100
stl.loop 30.320 30.921 32.56819 31.2210 31.5210 55.836 100
stl.lib 30.319 30.920 31.64063 31.2205 31.6705 50.133 100
rcpp.pure 9.907 10.807 10.95122 10.8070 11.1070 12.909 100
因此,通过Rcpp
的矩阵求和比R慢约2微秒,但比std::vector
和c型阵列设置快得多。
Q.E.D?
相关文章:
- C++LDAP检查用户是否是特定组的成员
- 检查某些类型是否是模板类 std::optional 的实例化
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- 如何检查模板专用化是否是基本模板的子类?
- 如何检查变量是否是C++中的地图?
- C++ Chrono 确定一天是否是周末?
- 将相同共享指针的副本存储在不同的向量中是否是一种好的做法?
- 使用类在C++中存储和列出变量/方法是否是一种好的做法
- 代码在 CodeSignal 中工作不正确。不确定这是否是我的代码缺陷
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- MFC 中的窗口消息管理:添加基类调用是否是强制性的?
- 检查 n2 是否是 n1 的倍数后结果错误,但根本没有错误
- C ++:检查它是否是类中的数字
- 传递给放置 new 的指针是否是指向其对象表示形式的非 UB 指针?
- 使用 SET(C++) 检查两个给定字符串是否是字谜时出现运行时错误
- 从 std::string 到 std::array<char,size> 的 memcopy 额外数据是否是一种未定义的行为?
- 有没有办法检查发送到变量的值是否是正确的类型,而它已经在该变量下?
- 如何检查一个模板是否是另一个模板的类成员
- 有没有办法检查用户输入是否是数字?
- r语言 - 在C++中使用 RCPP 的 NumericMatrix 循环是否是一个好的理想?