关于c ++:uniform_int_distribution的变化范围

Vary range of uniform_int_distribution

所以我有一个随机对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef unsigned int uint32;

class Random {
public:
    Random() = default;
    Random(std::mt19937::result_type seed) : eng(seed) {}

private:
    uint32 DrawNumber();
    std::mt19937 eng{std::random_device{}()};
    std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX};
};

uint32 Random::DrawNumber()
{
    return uniform_dist(eng);
}

我可以(通过另一个函数或其他功能)改变分布上限的最佳方法是什么?

(也愿意就其他样式问题提出建议)


分发对象是轻量级的。需要随机数时,只需构造一个新的分布。我在游戏引擎中使用了这种方法,并且在进行基准测试后,可以媲美使用良好的旧版rand()

此外,我还问过如何在GoingNative 2013直播中更改发行范围,标准委员会成员Stephen T. Lavavej建议仅创建新发行版,因为这不应该是性能问题。

这是我编写代码的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 eng{std::random_device{}()};
};

uint32 Random::DrawNumber(uint32 min, uint32 max)
{
    return std::uniform_int_distribution<uint32>{min, max}(eng);
}


您可以简单地创建std::uniform_int_distribution::param_type并使用param()方法修改范围。您可以使用decltype减少模板噪音:

1
2
decltype(uniform_dist.param()) new_range (0, upper);
uniform_dist.param(new_range);

我为示例制作了DrawNumber函数public。您可以提供一个上限,然后将新的uniform_int_distribution::param_type传递给uniform_int_distribution::operator()

param_type可以使用与相应发行版相同的参数来构造。

根据N3337,第26.5.1.6/9条[rand.req.dist]

For each of the constructors of D taking arguments corresponding to parameters of the distribution, P shall have a corresponding constructor subject to the same requirements and taking arguments identical in number, type, and default values. Moreover, for each of the member functions of D that return values corresponding to parameters of the distribution, P shall have a corresponding member function with the identical name, type, and semantics.

其中D是随机数分布函数对象的类型,而P是由D的相关param_type命名的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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 eng{std::random_device{}()};
    std::uniform_int_distribution<uint32> uniform_dist{0, 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;
}