根据https://stackoverflow.com/a/48676389/3846213和https://stackoverflow.com/a/5234293/3846213,R向量限制为2 ^ 31-1个项目。但是,我已经能够通过Rcpp触发“负长度向量不允许”错误(这被认为是试图分配一个太大的向量的标志),错误发生次数为该数目的一半。所有这些都来自于我尝试调试基于Rcpp的R软件包(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应该有一些特殊之处。
答案 0 :(得分:4)
问题是乘法溢出。当你做
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