在R中,我可以构建以下roll_die(seed = NULL)
函数,该函数返回1到6之间的随机整数,并且允许为RNG指定种子的选项。
roll_die_r <- function(seed = NULL){
# Returns a random number between 1 and 6
# Optionally specify a RNG seed
set.seed(seed)
return(sample(x = 1:6, size = 1L))
}
这很好,因为我可以使用默认的seed = NULL
来调用它并获取随机值或,也可以使用指定的种子值来调用它,以便获得可重复的结果。
roll_die_r() # random
roll_die_r(seed = 0) # always returns 6
如何使用mt19937在c ++中实现相同的功能?我能想到的最好的是
#include <Rcpp.h>
#include <random>
using namespace Rcpp;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
int roll_die_cpp(int seed = -1){
// Returns a random integer between 1 and 6
// Optionally specify a RNG seed
std::mt19937 mt;
// Seed the RNG
if(seed == -1) seed = std::random_device{}();
mt.seed(seed);
std::uniform_int_distribution<int> dist(1, 6);
int result = dist(mt);
return result;
}
但这并不理想,因为用户可能会意外call roll_die_cpp(seed = -1)
并期望获得可重现的结果,而不是这种情况。
roll_die_cpp() # random
roll_die_cpp(seed = 0) # always returns 5
roll_die_cpp(seed = -1) # random
我的问题不是专门针对roll_die()
方法或随机数生成器,而是有关函数设计的。在R中,我经常使用默认参数设置为NULL的函数,但我不知道如何在c ++中完成相同的工作。
更新: 这是我要得到的另一个例子。
R函数
return_0 <- function(msg = NULL){
if(!is.null(msg)) print(msg)
return(0L)
}
return_0() # doesn't print a message
return_0("hello world") # prints hello world
cpp功能
// [[Rcpp::export]]
int return_0_cpp(std::string msg = "don't print"){
if(msg != "don't print") Rcpp::Rcout << msg;
return(0);
}
return_0_cpp() # doesn't print a message
return_0_cpp(msg = "hello world") # prints hello world
return_0_cpp(msg = "don't print") # doesn't print a message
请注意return_0_cpp()
多么尴尬。在cpp中用R创建的干净方法是什么?
答案 0 :(得分:2)
在R中,我经常使用默认参数设置为NULL的函数,但我不知道如何 在c ++中完成同样的事情。
std::optional
(自C ++ 17起)用于可选值:
#include <iostream>
#include <optional>
void fun(std::optional<int> v = std::nullopt) {
if (v) {
std::cout << "value passed = " << v.value();
} else {
std::cout << "no value passed";
}
}
int main(){
fun();
fun(4);
}
作为旁注:根据传递的参数数量,使同一个函数执行两项不同的操作时要小心。有人可能会争辩
dice.seed(0);
auto x = dice.roll();
比
更明确和可读auto x = dice.roll(0);
答案 1 :(得分:1)
我经常使用仅标头的库,其工作方式如下(大大简化了):
namespace ran {
inline std::mt19937& generator()
{
thread_local static std::mt19937 mt{std::random_device{}()};
return mt;
}
template<typename Integral>
void seed(Integral n)
{
generator().seed(std::mt19937::result_type(n));
}
template<typename Integral>
Integral number(Integral min, Integral max)
{
using dist_type = typename std::uniform_int_distribution<Integral>;
thread_local static dist_type dist;
return dist(generator(), typename dist_type::param_type(min, max));
}
} // namespace ran
使用thread_local static
可确保线程安全并保持性能。它可以重复使用相同的随机数生成器,仅在开始时就播种一次,也可以随时使用特定值重新播种。
int main()
{
for(auto i = 0; i < 10; ++i)
std::cout << ran::number(3, 9) << ' ';
std::cout << '\n';
ran::seed(5);
for(auto i = 0; i < 10; ++i)
std::cout << ran::number(3, 9) << ' ';
std::cout << '\n';
}