有效地在Rcpp中生成随机比特流

问题描述 投票:1回答:1

我在目前正在建立的名为rbinom01的R包中有一个辅助功能。请注意,它调用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.

我前往the Document,它说我可以使用其中一个*_rand功能,以及一个distribution functions家庭。那很酷,但我的包只需要一串随机位而不是随机的double。我能拥有它的最简单的方法是使用random(3)或者从/dev/urandom读取,但这使得我的包“不可移植”。

This post建议使用sample,但不幸的是它不适合我的用例。对于我的应用程序,生成随机位显然对性能至关重要,因此我不希望它浪费任何时间调用unif_rand,将结果乘以N并将其四舍五入。无论如何,我使用C ++的原因是利用位级并行。

当然,我可以手动滚动我自己的PRNG或复制并粘贴像xoshiro256**这样的最先进的PRNG的代码,但在此之前,我想看看是否有更容易的替代方案。

顺便说一下,有人可以把一个很好的Rcpp简短教程链接到我身上吗?编写R扩展是全面而且令人敬畏的,但它需要几个星期才能完成。我正在寻找一个更简洁的版本,但最好是它应该比调用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;
}
c++ r random rcpp r-package
1个回答
4
投票

有不同的R包使PRNG可用作C ++标头库:

  • BH:来自boost.random的一切
  • sitmo:各种Threefry版本
  • kxxswpoi:PCG家族,hoshiro256 +和choroshiro128 +
  • ...

您可以通过将dqrng添加到包的LinkingTo中来利用其中任何一种。通常这些PRNG是在C ++ 11 DECRIPTION标题之后建模的,这意味着你必须控制它们的生命周期并自己播种。在单线程环境中,我喜欢使用匿名命名空间进行生命周期控制,例如:

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之外,必须阅读convenient wrapper插图。 Hadley Wickham的Rcpp package也有一章关于“编译代码”,如果你想去R Packages方式。

© www.soinside.com 2019 - 2024. All rights reserved.