使用 Rcpp 属性允许 C++ 常量作为默认函数参数 [英] Allow C++ constants to be a default function parameter using Rcpp Attributes
问题描述
我在带有 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_MAX
和LLONG_MIN
指定数值,这将满足直接在函数上使用 Rcpp 属性的条件.但是,这些值是特定于实现的.因此,对它们进行硬编码并不理想.因此,我们必须寻求外部解决方案:Rcpp::Nullable
类以启用默认的NULL
值.之所以要用Rcpp::Nullable
来包裹参数类型,是因为NULL
很特殊,不小心会让人心痛.If you were to specify numerical values for
LLONG_MAX
andLLONG_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: theRcpp::Nullable<T>
class to enable the defaultNULL
value. The reason why we have to wrap the parameter type withRcpp::Nullable<T>
is thatNULL
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: useRcpp::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屋!