【问题标题】:Allow C++ constants to be a default function parameter using Rcpp Attributes使用 Rcpp 属性允许 C++ 常量成为默认函数参数
【发布时间】:2017-04-19 02:58:26
【问题描述】:

我使用 rcpp 在 R 包中创建了一个 cumsum 函数,它将对一个向量进行累积求和,直到它达到用户定义的天花板或地板。但是,如果希望 cumsum 有界,用户仍然必须指定一个楼层。

例子:

a = c(1, 1, 1, 1, 1, 1, 1)

如果我想 cumsum a 并且上限为 3,我可以 cumsum_bounded(a, lower = 1, upper = 3)。我宁愿不必指定下限。

我的代码:

#include <Rcpp.h>
#include <float.h>
#include <cmath>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector cumsum_bounded(NumericVector x, int upper, int lower) {
  NumericVector res(x.size());
  double acc = 0;
  for (int i=0; i < x.size(); ++i) {
    acc += x[i];
    if (acc < lower)  acc = lower;
    else if (acc > upper)  acc = upper;
    res[i] = acc;
  }
  return res;
}

我想要什么:

#include <Rcpp.h>
#include <float.h>
#include <cmath>
#include <climits> //for LLONG_MIN and LLONG_MAX
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector cumsum_bounded(NumericVector x, long long int upper = LLONG_MAX, long long int lower = LLONG_MIN) {
  NumericVector res(x.size());
  double acc = 0;
  for (int i=0; i < x.size(); ++i) {
    acc += x[i];
    if (acc < lower)  acc = lower;
    else if (acc > upper)  acc = upper;
    res[i] = acc;
  }
  return res;
}

【问题讨论】:

    标签: r rcpp


    【解决方案1】:

    简而言之,是的,这是可能的,但它需要技巧,包括创建中间函数或在主函数中嵌入排序逻辑。


    总之,Rcpp 属性只支持一组值的限制特征。这些值列在Rcpp FAQ 3.12 entry

    • 用引号分隔的字符串字面量(例如“foo”)
    • 整数和十进制数值(例如 10 或 4.5)
    • 预定义常量包括:
      • 布尔值:真假
      • 空值:R_NilValue、NA_STRING、NA_INTEGER、NA_REAL 和 NA_LOGICAL。
    • 可以使用 ::create 静态成员函数的空形式。
      • CharacterVector、IntegerVector 和 NumericVector
    • 使用行、列构造函数 Rcpp::Matrix n(rows,cols) 实例化的矩阵类型
      • CharacterMatrix、IntegerMatrix 和 NumericMatrix)

    如果您要为 LLONG_MAXLLONG_MIN 指定数值,这将符合直接在函数上使用 Rcpp 属性的条件。但是,这些值是特定于实现的。因此,对它们进行硬编码并不理想。因此,我们必须寻求外部解决方案:Rcpp::Nullable&lt;T&gt; 类来启用默认的NULL 值。之所以必须将参数类型用Rcpp::Nullable&lt;T&gt;包裹起来,是因为NULL非常特殊,一不小心就会让人心痛。

    NULL 值与实数行上的其他值不同,在这种情况下不会用于绑定您的值。因此,它是用于函数调用的完美候选者。然后您必须做出两个选择:使用Rcpp::Nullable&lt;T&gt; 作为主函数的参数,或者创建一个具有正确参数的“逻辑”辅助函数,并且可以在应用程序的其他地方使用而无需担心。我选择了下面的后者。

    #include <Rcpp.h>
    #include <float.h>
    #include <cmath>
    #include <climits> //for LLONG_MIN and LLONG_MAX
    using namespace Rcpp;
    
    NumericVector cumsum_bounded_logic(NumericVector x,
                                       long long int upper = LLONG_MAX,
                                       long long int lower = LLONG_MIN) {
    
        NumericVector res(x.size());
        double acc = 0;
        for (int i=0; i < x.size(); ++i) {
            acc += x[i];
            if (acc < lower)  acc = lower;
            else if (acc > upper)  acc = upper;
            res[i] = acc;
        }
    
        return res;
    }
    
    // [[Rcpp::export]]
    NumericVector cumsum_bounded(NumericVector x,
                                 Rcpp::Nullable<long long int> upper = R_NilValue, 
                                 Rcpp::Nullable<long long int> lower = R_NilValue) {
    
        if(upper.isNotNull() && lower.isNotNull()){
            return cumsum_bounded_logic(x, Rcpp::as< long long int >(upper), Rcpp::as< long long int >(lower));
        } else if(upper.isNull() && lower.isNotNull()){
            return cumsum_bounded_logic(x, LLONG_MAX, Rcpp::as< long long int >(lower));
        } else if(upper.isNotNull() && lower.isNull()) {
            return cumsum_bounded_logic(x, Rcpp::as< long long int >(upper), LLONG_MIN);
        } else {
            return cumsum_bounded_logic(x, LLONG_MAX, LLONG_MIN);
        }
    
        // Required to quiet compiler
        return x;
    }
    

    测试输出

    cumsum_bounded(a, 5)
    ## [1] 1 2 3 4 5 5 5
    cumsum_bounded(a, 5, 2)
    ## [1] 2 3 4 5 5 5 5
    

    【讨论】:

    • 构建包时出现以下错误:Warning messages: 1: Unable to parse C++ default value 'LLONG_MAX' for argument upper of function cumsum_bounded_logic 2: Unable to parse C++ default value 'LLONG_MIN' for argument lower of function cumsum_bounded_logic
    • 复制并粘贴我上面的内容。不要将// [[Rcpp::export] 添加到cumsum_bounded_logic 函数中..
    • 谢谢你,我有一个挥之不去的// [[Rcpp::export]
    猜你喜欢
    • 1970-01-01
    • 2015-02-20
    • 2018-04-30
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    相关资源
    最近更新 更多