为什么我的 Rcpp 平均函数比 R 慢? [英] Why is my Rcpp mean function slower than R?

查看:79
本文介绍了为什么我的 Rcpp 平均函数比 R 慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个 C++ 函数,将 x 中的每个元素提升到 power 并取平均值.我创建了三个版本:

I want to create a C++ function that raises each element in x to power and takes the mean. I've created three versions:

  • power_mean_R: R 解决方案 -- mean(x^power)
  • power_mean_C: C++ 解决方案
  • power_mean_C_2arg: C++ 带有额外 power 参数的解决方案
  • power_mean_R: R solution -- mean(x^power)
  • power_mean_C: C++ solution
  • power_mean_C_2arg: C++ solution with extra power argument

额外的 power 参数似乎大大减慢了函数的速度,以至于它比 R 实现慢.这是使用 Rcpp 的现实还是我可以改进我的代码?

The extra power argument seems to drastically slow down the function to the point that it's slower than the R implementation. Is this a reality of using Rcpp or is there something I can improve in my code?

#library(Rcpp)

cppFunction(
    'double power_mean_C_2arg(NumericVector x, double power) {

        int n = x.size();
        double total = 0;

        for(int i=0; i<n; ++i) {
            total += pow(x[i], power);
        }

        return total / n;

    }'
)

cppFunction(
    'double power_mean_C(NumericVector x) {

        int n = x.size();
        double total = 0;

        for(int i=0; i<n; ++i) {
            total += pow(x[i], 2);
        }

        return total / n;

    }'
)

power_mean_R <- function(x, power) {
    mean(x^power)
}

bench::mark(
    R = power_mean_R(1:100, p = 2),
    C = power_mean_C(1:100),
    C2arg = power_mean_C_2arg(x = 1:100, p = 2)
)

  expression    min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result memory
  <bch:expr> <bch:> <bch:>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list> <list>
1 R          5.91µs 6.91µs   112386.    1.27KB      0   10000     0       89ms <dbl … <Rpro…
2 C          2.87µs 3.54µs   231281.    3.32KB     23.1  9999     1     43.2ms <dbl … <Rpro…
3 C2arg      6.02µs 6.89µs   116187.    3.32KB      0   10000     0     86.1ms <dbl … <Rpro…

推荐答案

您提供的示例几乎不会妨碍您的 C++ 功能

There are few things that handicap your C++ function with the examples you gave

1:100 是一个 ALTREP 序列,为此存在一种高度优化的 sum 方法,速度要快得多.在下面的极端例子中,它快了 600 万倍.显然,该向量并非一直都是 altrep,但在 altrep 序列上进行基准测试是个坏主意.

1:100 is an ALTREP sequence, for which a highly optimized sum method exists which is much faster. In the below extreme examples, it's over 6 million times faster. Obviously the vector is not altrep all the way through, but it's a bad idea to benchmark on altrep sequences.

billion <- c(1L, 2:1e9)
billalt <- 1:1e9

identical(billion, billalt)
#> [1] TRUE

bench::mark(sum(billion), sum(billalt))
#> # A tibble: 2 x 10
#>   expression             min            mean          median          max
#>   <chr>             <bch:tm>        <bch:tm>        <bch:tm>     <bch:tm>
#> 1 sum(billi~ 614564900.000ns 614564900.000ns 614564900.000ns 614564.900us
#> 2 sum(billa~       100.000ns       312.530ns       200.000ns     23.300us
#> # ... with 5 more variables: `itr/sec` <dbl>, mem_alloc <bch:byt>, n_gc <dbl>,
#> #   n_itr <int>, total_time <bch:tm>

reprex 包 (v0.3.0) 于 2020 年 12 月 11 日创建

Created on 2020-12-11 by the reprex package (v0.3.0)

其次,1:100 是一个整数向量,但是你的 Rcpp 函数接受一个数字向量,所以数据必须被强制类型为 double 在任何操作完成之前.对于如此小的向量,它可能是开销的很大一部分.

Second, 1:100 is an integer vector but your Rcpp function accepts a numeric vector, so the data must be coerced to type double before any operations are done. For a vector so small, it's likely to be a considerable part of the overhead.

您的测试向量非常小,因此像 Rcpp 保留随机种子这样的开销将主导差异.

Your test vector is very small so overheads like Rcpp's preservation of random seeds are going to dominate the differences.

这篇关于为什么我的 Rcpp 平均函数比 R 慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆