Rcpp R 向量大小限制(不允许负长度向量)
Rcpp R vector size limit (negative length vectors are not allowed)
根据 and R vectors are limited 2^31 - 1 items. However, I've been able to trigger the "negative length vectors are not allowed" error (which is supposed to be a sign of trying to allocate an overly large vector) at half that number via Rcpp. This all comes from my trying to debug an Rcpp-based R package (https://github.com/tpq/propr/issues/13).
library(Rcpp)
cppFunction("
IntegerVector test(int size) {
int veclen = size * (size - 1) / 2;
IntegerVector vec(veclen);
return vec;
}
")
vec <- test(47000)
Error in test(47000) : negative length vectors are not allowed
47000^2 / 2 几乎是 2^31 的一半。
我在纯 R 中没有这样的问题,也就是说 vec <- 1:(47000*(47000-1)/2)
运行良好,所以 Rcpp 应该有一些特别之处。
问题是乘法溢出。当你这样做时
size * (size - 1) / 2
操作顺序让你头疼,因为
size * (size - 1)
即使整个表达式不会溢出,也可能会溢出。
我们可以通过添加打印语句来看到这一点:
IntegerVector test(int size) {
int veclen = size * (size - 1) / 2;
Rcpp::Rcout << veclen << std::endl;
IntegerVector vec(veclen);
return vec;
}
vec <- test(47000)
# -1043007148
所以,我们可以通过改变我们执行该操作的方式来修复它:
IntegerVector test(int size) {
int veclen = (size / 2) * (size - 1);
Rcpp::Rcout << veclen << std::endl;
IntegerVector vec(veclen);
return vec;
}
没有问题
vec <- test(47000)
# 1104476500
str(vec)
# int [1:1104476500] 0 0 0 0 0 0 0 0 0 0 ...
更新:奇数问题
Eli Korvigo 在关于奇数整数除法行为的评论中提出了一个很好的观点。为了说明,请考虑使用偶数 4 和奇数 5
调用函数
even <- 4
odd <- 5
even * (even - 1) / 2
# [1] 6
odd * (odd - 1) / 2
# [1] 10
它应该分别创建长度为 6 和 10 的向量。
但是,会发生什么?
test(4)
# 6
# [1] 0 0 0 0 0 0
test(5)
# 8
# [1] 0 0 0 0 0 0 0 0
哦不!
5 / 2
在整数除法中是 2,而不是 2.5,所以在奇怪的情况下这并不能完全满足我们的要求。
然而,幸运的是我们可以通过简单的流量控制轻松解决这个问题:
IntegerVector test2(int size) {
int veclen;
if ( size % 2 == 0 ) {
veclen = (size / 2) * (size - 1);
} else {
veclen = size * ((size - 1) / 2);
}
Rcpp::Rcout << veclen << std::endl;
IntegerVector vec(veclen);
return vec;
}
我们可以看到这可以很好地处理奇数和偶数情况:
test2(4)
# 6
# [1] 0 0 0 0 0 0
test2(5)
# 10
# [1] 0 0 0 0 0 0 0 0 0 0
根据 and R vectors are limited 2^31 - 1 items. However, I've been able to trigger the "negative length vectors are not allowed" error (which is supposed to be a sign of trying to allocate an overly large vector) at half that number via Rcpp. This all comes from my trying to debug an Rcpp-based R package (https://github.com/tpq/propr/issues/13).
library(Rcpp)
cppFunction("
IntegerVector test(int size) {
int veclen = size * (size - 1) / 2;
IntegerVector vec(veclen);
return vec;
}
")
vec <- test(47000)
Error in test(47000) : negative length vectors are not allowed
47000^2 / 2 几乎是 2^31 的一半。
我在纯 R 中没有这样的问题,也就是说 vec <- 1:(47000*(47000-1)/2)
运行良好,所以 Rcpp 应该有一些特别之处。
问题是乘法溢出。当你这样做时
size * (size - 1) / 2
操作顺序让你头疼,因为
size * (size - 1)
即使整个表达式不会溢出,也可能会溢出。 我们可以通过添加打印语句来看到这一点:
IntegerVector test(int size) {
int veclen = size * (size - 1) / 2;
Rcpp::Rcout << veclen << std::endl;
IntegerVector vec(veclen);
return vec;
}
vec <- test(47000)
# -1043007148
所以,我们可以通过改变我们执行该操作的方式来修复它:
IntegerVector test(int size) {
int veclen = (size / 2) * (size - 1);
Rcpp::Rcout << veclen << std::endl;
IntegerVector vec(veclen);
return vec;
}
没有问题
vec <- test(47000)
# 1104476500
str(vec)
# int [1:1104476500] 0 0 0 0 0 0 0 0 0 0 ...
更新:奇数问题
Eli Korvigo 在关于奇数整数除法行为的评论中提出了一个很好的观点。为了说明,请考虑使用偶数 4 和奇数 5
调用函数even <- 4
odd <- 5
even * (even - 1) / 2
# [1] 6
odd * (odd - 1) / 2
# [1] 10
它应该分别创建长度为 6 和 10 的向量。 但是,会发生什么?
test(4)
# 6
# [1] 0 0 0 0 0 0
test(5)
# 8
# [1] 0 0 0 0 0 0 0 0
哦不!
5 / 2
在整数除法中是 2,而不是 2.5,所以在奇怪的情况下这并不能完全满足我们的要求。
然而,幸运的是我们可以通过简单的流量控制轻松解决这个问题:
IntegerVector test2(int size) {
int veclen;
if ( size % 2 == 0 ) {
veclen = (size / 2) * (size - 1);
} else {
veclen = size * ((size - 1) / 2);
}
Rcpp::Rcout << veclen << std::endl;
IntegerVector vec(veclen);
return vec;
}
我们可以看到这可以很好地处理奇数和偶数情况:
test2(4)
# 6
# [1] 0 0 0 0 0 0
test2(5)
# 10
# [1] 0 0 0 0 0 0 0 0 0 0