使用 Rcpp 属性允许 C++ 常量作为默认函数参数 [英] Allow C++ constants to be a default function parameter using Rcpp Attributes

查看:38
本文介绍了使用 Rcpp 属性允许 C++ 常量作为默认函数参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在带有 rcpp 的 R 包中创建了一个 cumsum 函数,它将累积一个向量,直到它达到用户定义的天花板或地板.但是,如果想要将 cumsum 限制在上面,用户仍然必须指定一个楼层.

I created a cumsum function in an R package with rcpp which will cumulatively sum a vector until it hits the user defined ceiling or floor. However, if one wants the cumsum to be bounded above, the user must still specify a floor.

示例:

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

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

If i wanted to cumsum a and have an upper bound of 3, I could cumsum_bounded(a, lower = 1, upper = 3). I would rather not have to specify the lower bound.

我的代码:

#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;
}

推荐答案

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

In short, yes its possible but it requires finesse that involves creating an intermediary function or embedding sorting logic within the main function.

总而言之,Rcpp 属性仅支持值的限制特征集.这些值列在 Rcpp 常见问题解答中3.12入口

In long, Rcpp attributes only supports a limit feature set of values. These values are listed in the Rcpp FAQ 3.12 entry

  • 用引号分隔的字符串文字(例如foo")
  • 整数和十进制数值(例如 10 或 4.5)
  • 预定义常量包括:
    • 布尔值:true 和 false
    • 空值:R_NilValue、NA_STRING、NA_INTEGER、NA_REAL 和 NA_LOGICAL.
    • CharacterVector、IntegerVector 和 NumericVector
    • CharacterMatrix、IntegerMatrix 和 NumericMatrix)

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

    If you were to specify numerical values for LLONG_MAX and LLONG_MIN this would meet the criteria to directly use Rcpp attributes on the function. However, these values are implementation specific. Thus, it would not be ideal to hardcode them. Thus, we have to seek an outside solution: the Rcpp::Nullable<T> class to enable the default NULL value. The reason why we have to wrap the parameter type with Rcpp::Nullable<T> is that NULL is a very special and can cause heartache if not careful.

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

    The NULL value, unlike others on the real number line, will not be used to bound your values in this case. As a result, it is the perfect candidate to use on the function call. There are two choices you then have to make: use Rcpp::Nullable<T> as the parameters on the main function or create a "logic" helper function that has the correct parameters and can be used elsewhere within your application without worry. I've opted for the later below.

    #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;
    }
    

    <小时>

    测试输出


    Test Output

    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
    

    这篇关于使用 Rcpp 属性允许 C++ 常量作为默认函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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