改变 uniform_int_distribution 的范围
Posted
技术标签:
【中文标题】改变 uniform_int_distribution 的范围【英文标题】:Vary range of uniform_int_distribution 【发布时间】:2013-10-02 21:18:47 【问题描述】:所以我有一个随机对象:
typedef unsigned int uint32;
class Random
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed)
private:
uint32 DrawNumber();
std::mt19937 engstd::random_device();
std::uniform_int_distribution<uint32> uniform_dist0, UINT32_MAX;
;
uint32 Random::DrawNumber()
return uniform_dist(eng);
我可以改变(通过另一个函数或其他方式)分布上限的最佳方法是什么?
(也愿意就其他风格问题征求意见)
【问题讨论】:
在首次初始化distribution
后,您无法更改它们的边界。您应该如何进行很大程度上取决于您使用随机数的目的以及为什么需要更改边界。
@us2012 这是错误的;你可以。
Use std::uniform_int_distribution and define its range later 的可能重复项(先发制人的反对意见:是的,这是较新的,并且标题有点切题,但 IMO 它有一个更切题的答案,而且通常能更快地切入主题)
冒着偏见的风险,这两个不同的问题具有基本相同的公认答案 - “另一种方法是添加方法......”另一个问题的答案的一部分与在这里接受答案。这个答案还包括使用,带有 std::mt19937。也就是说.param
方法是新的。由于这个问题现在已经 5 年了,也许最好的做法是将另一个标记为重复并在此处修改接受的答案?或者,只需将问题保持原样:)
【参考方案1】:
分发对象是轻量级的。当您需要一个随机数时,只需构建一个新分布即可。我在游戏引擎中使用了这种方法,经过基准测试,它与使用旧的 rand()
相当。
另外,我询问了如何在 GoingNative 2013 直播中改变分发范围,标准委员会成员 Stephen T. Lavavej 建议简单地创建新分发,因为它不应该是表演问题。
我会这样写你的代码:
using uint32 = unsigned int;
class Random
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed)
uint32 DrawNumber(uint32 min, uint32 max);
private:
std::mt19937 engstd::random_device();
;
uint32 Random::DrawNumber(uint32 min, uint32 max)
return std::uniform_int_distribution<uint32>min, max(eng);
【讨论】:
我想我刚刚看了 Going Native 流 :) 虽然,我对 C++(尤其是 C++11)(特别是 C++11)还是(有点)新手,而且其中相当多的内容超出了我的想象 :L如果您确定每次创建新发行版都没有显着开销,我可能会这样做 我已经对其进行了基准测试。开销很小,可以忽略。 (这是一个微优化纳粹所说的)。此外,没有其他方法可以改变分布的界限。 好的,太好了,非常感谢 :) 我可能会使用常数 0 作为最小值,并将 UINT32_MAX 作为最大值的默认值。 这创建一个新的发行版,而不是修改现有的发行版。因此,无论类实例化的速度有多快,它都无法回答问题。 通过谷歌找到了这个答案,我很担心。每次构造Random
时,您都在创建一个新的 std::mt19937
引擎对象;与 S.T.L. 完全相反。建议...【参考方案2】:
我正在为我的示例创建DrawNumber
函数public
。您可以提供一个采用上限的重载,然后将新的uniform_int_distribution::param_type
传递给uniform_int_distribution::operator()
param_type
可以使用与对应分布相同的参数来构造。
从 N3337,§26.5.1.6/9 [rand.req.dist]
对于
D
的每个构造函数,其参数对应于分布的参数,P
应有一个对应的构造函数,其要求相同,参数数量、类型和默认值相同。此外,对于D
的每个返回值对应分布参数的成员函数,P
应该有一个对应的成员函数,其名称、类型和语义都相同。
其中D
是随机数分布函数对象的类型,P
是D
关联的param_type
命名的类型
#include <iostream>
#include <random>
typedef unsigned int uint32;
class Random
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed)
uint32 DrawNumber();
uint32 DrawNumber(uint32 ub);
private:
std::mt19937 engstd::random_device();
std::uniform_int_distribution<uint32> uniform_dist0, UINT32_MAX;
;
uint32 Random::DrawNumber()
return uniform_dist(eng);
uint32 Random::DrawNumber(uint32 ub)
return uniform_dist(eng, decltype(uniform_dist)::param_type(0, ub));
int main()
Random r;
std::cout << r.DrawNumber() << std::endl;
std::cout << r.DrawNumber(42) << std::endl;
【讨论】:
【参考方案3】:您可以简单地创建一个std::uniform_int_distribution<uint32>::param_type
并使用param()
方法修改范围。您可以使用decltype
减少模板噪音:
decltype(uniform_dist.param()) new_range (0, upper);
uniform_dist.param(new_range);
【讨论】:
以上是关于改变 uniform_int_distribution 的范围的主要内容,如果未能解决你的问题,请参考以下文章