[英]Generating a random bit stream in Rcpp efficiently
我正在构建的R包中有一个辅助功能,名为rbinom01
。 请注意,它调用random(3)
。
int rbinom01(int size) {
if (!size) {
return 0;
}
int64_t result = 0;
while (size >= 32) {
result += __builtin_popcount(random());
size -= 32;
}
result += __builtin_popcount(random() & ~(LONG_MAX << size));
return result;
}
当R CMD check my_package
,出现以下警告:
* checking compiled code ... NOTE
File ‘ my_package/libs/my_package.so’:
Found ‘_random’, possibly from ‘random’ (C)
Object: ‘ my_function.o’
Compiled code should not call entry points which might terminate R nor
write to stdout/stderr instead of to the console, nor use Fortran I/O
nor system RNGs.
See ‘Writing portable packages’ in the ‘Writing R Extensions’ manual.
我前往文档 ,它说我可以使用*_rand
函数之一,以及一系列分发函数 。 很好,但是我的包只需要一个随机位流,而不是一个随机double
。 我拥有它的最简单方法是使用random(3)
或从/dev/urandom
读取,但这会使我的程序包“无法携带”。
这篇文章建议使用sample
,但是不幸的是,它不适合我的用例。 对于我的应用程序,生成随机位显然对性能至关重要,因此我不希望浪费时间调用unif_rand
,将结果乘以N
并四舍五入。 无论如何,我使用C ++的原因是为了利用位级并行性。
当然,我可以手动滚动自己的PRNG或复制并粘贴最先进的PRNG的代码,例如xoshiro256 ** ,但是在此之前,我想看看是否有更简单的替代方法。
顺便说一句,有人可以将Rcpp的简短教程链接到我吗? 编写R Extensions非常全面而且很棒,但是我可能要花几周的时间才能完成。 我正在寻找一个更简洁的版本,但最好它应该比对Rcpp.package.skeleton
的调用提供更多信息。
如@Ralf Stubner的答案所建议,我重新编写了原始代码,如下所示。 但是,每次都得到相同的结果。 如何正确植入种子,同时保持代码“可移植”?
int rbinom01(int size) {
dqrng::xoshiro256plus rng;
if (!size) {
return 0;
}
int result = 0;
while (size >= 64) {
result += __builtin_popcountll(rng());
Rcout << sizeof(rng()) << std::endl;
size -= 64;
}
result += __builtin_popcountll(rng() & ((1LLU << size) - 1));
return result;
}
有不同的R包使PRNG可用作仅C ++头文件库:
您可以通过将LinkingTo
添加到包的DECRIPTION
来使用其中的任何一个。 通常,这些PRNG是根据C ++ 11 random
标头建模的,这意味着您必须控制它们的生命周期并自行设定种子。 在单线程环境中,我喜欢使用匿名名称空间进行生命周期控制,例如:
#include <Rcpp.h>
// [[Rcpp::depends(dqrng)]]
#include <xoshiro.h>
// [[Rcpp::plugins(cpp11)]]
namespace {
dqrng::xoshiro256plus rng{};
}
// [[Rcpp::export]]
void set_seed(int seed) {
rng.seed(seed);
}
// [[Rcpp::export]]
int rbinom01(int size) {
if (!size) {
return 0;
}
int result = 0;
while (size >= 64) {
result += __builtin_popcountll(rng());
size -= 64;
}
result += __builtin_popcountll(rng() & ((1LLU << size) - 1));
return result;
}
/*** R
set_seed(42)
rbinom01(10)
rbinom01(10)
rbinom01(10)
*/
但是,使用runif
并不一定比访问/dev/urandom
更快,而且速度更快。 在dqrng
有一个方便的包装器 。
至于教程:除WRE之外, Rcpp软件包插图也是必读的。 如果您想使用devtools
-way,Hadley Wickham撰写的R Packages也有一章“编译的代码”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.