bernoulli_distribution 对比 uniform_int_distribution
bernoulli_distribution vs uniform_int_distribution
在比较 bernoulli_distribution
的默认构造函数(true/false 的概率为 50/50)和 uniform_int_distribution{0, 1}
(概率为 0 或 1)时,我发现 bernoulli_distribution
s 至少比 uniform_int_distribution
慢 2 倍和 6 倍以上 ,尽管它们给出了相同的结果。
我希望 bernoulii_distribition
表现更好,因为它是专门为只有两种结果的概率而设计的,真或假;然而,它没有。
鉴于以上和以下性能指标,伯努利分布在 uniform_int_distributions 上是否有实际用途?
5 次运行的结果(发布模式,x64 位):
(有关未附加调试器的发布运行,请参阅下面的编辑)
bernoulli: 58 ms
false: 500690
true: 499310
uniform: 9 ms
1: 499710
0: 500290
----------
bernoulli: 57 ms
false: 500921
true: 499079
uniform: 9 ms
0: 499614
1: 500386
----------
bernoulli: 61 ms
false: 500440
true: 499560
uniform: 9 ms
0: 499575
1: 500425
----------
bernoulli: 59 ms
true: 498798
false: 501202
uniform: 9 ms
1: 499485
0: 500515
----------
bernoulli: 58 ms
true: 500777
false: 499223
uniform: 9 ms
0: 500450
1: 499550
----------
分析代码:
#include <chrono>
#include <random>
#include <iostream>
#include <unordered_map>
int main() {
auto gb = std::mt19937{std::random_device{}()};
auto bd = std::bernoulli_distribution{};
auto bhist = std::unordered_map<bool, int>{};
auto start = std::chrono::steady_clock::now();
for(int i = 0; i < 1'000'000; ++i) {
bhist[bd(gb)]++;
}
auto end = std::chrono::steady_clock::now();
auto dif = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "bernoulli: " << dif.count() << " ms\n";
std::cout << std::boolalpha;
for(auto& b : bhist) {
std::cout << b.first << ": " << b.second << '\n';
}
std::cout << std::noboolalpha;
std::cout << '\n';
auto gu = std::mt19937{std::random_device{}()};
auto u = std::uniform_int_distribution<int>{0, 1};
auto uhist = std::unordered_map<int, int>{};
start = std::chrono::steady_clock::now();
for(int i = 0; i < 1'000'000; ++i) {
uhist[u(gu)]++;
}
end = std::chrono::steady_clock::now();
dif = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "uniform: " << dif.count() << " ms\n";
for(auto& b : uhist) {
std::cout << b.first << ": " << b.second << '\n';
}
std::cout << '\n';
}
编辑
我重新运行 没有附加调试符号的测试,bernoulli 仍然 运行 慢了 4 倍:
bernoulli: 37 ms
false: 500250
true: 499750
uniform: 9 ms
0: 500433
1: 499567
-----
bernoulli: 36 ms
false: 500595
true: 499405
uniform: 9 ms
0: 499061
1: 500939
-----
bernoulli: 36 ms
false: 500988
true: 499012
uniform: 8 ms
0: 499596
1: 500404
-----
bernoulli: 36 ms
true: 500425
false: 499575
uniform: 8 ms
0: 499974
1: 500026
-----
bernoulli: 36 ms
false: 500847
true: 499153
uniform: 8 ms
0: 500082
1: 499918
-----
class bernoulli_distribution
用于生成可能不均匀比率的布尔值。为此,它必须在 [0,1] 范围内生成一个浮点数,然后将其与给定概率进行比较。或任何等价物。
很明显,此例程可能比采用随机整数模 2 慢 - 这几乎是从随机数在 {0,1}
中创建统一数所需的全部。
有什么好惊讶的?只有当编译器在编译期间知道它是 50/50 的同时以某种方式设法找出不必要的操作时,性能才能达到偶数。
默认构建的 std::bernoulli_distribution
对两种结果赋予相同的权重,但您可以为其赋予不同的分布参数以更改概率。这可能会导致额外的复杂性。更好的比较是使用 std::uniform_real_distribution<double>
并将其结果与 0.5 进行比较(默认情况下,它会给出 [0, 1)
范围内的随机数)。
See here 例如:
gcc 输出:
bernoulli: 28 ms
false: 499818
true: 500182
uniform: 31 ms
1: 500686
0: 499314
real: 29 ms
1: 500191
0: 499809
clang 输出:
bernoulli: 106 ms
false: 500662
true: 499338
uniform: 23 ms
1: 501263
0: 498737
real: 101 ms
1: 499683
0: 500317
使用 gcc 的结果大致相同(多次运行往往会给 uniform int 更长的时间,这与您看到的相反)。随着 clang 我得到 bernoulli 和 real 大致相同,而 uniform int 的时间要少得多。这两个都使用 -O3
.
一些评论和答案建议改用 uniform_real_distribution
。
我测试了 uniform_real_distribution(0.0f, nextafter(1.0f, 20.f))
(考虑到 urd
是半封闭范围)与 bernoulli_distribution
相比 bernoulli_distribution
快了大约 20%-25%不管概率如何(并给出 更正确的结果 。我测试了 1.0
真实概率,而我使用上述 urd
值的实现实际上给出了假阴性(授予一个或 5 次一百万次运行中的两次)并且 bernoulli
给出了正确的 none.
因此,速度方面:bernoulli_distribution
比 uniform_real_distribution
快但比 uniform_int_distribution
慢。
长话短说,使用正确的工具来完成工作,不要重新发明轮子,STL 构建良好等等,取决于用例,一个比另一个更好。
对于是-否概率(IsPercentChance(float probability)
),bernoulli_distribution
更快更好。
对于纯粹的“给我一个随机的随机布尔值”,uniform_int_distribution
更快更好。
在比较 bernoulli_distribution
的默认构造函数(true/false 的概率为 50/50)和 uniform_int_distribution{0, 1}
(概率为 0 或 1)时,我发现 bernoulli_distribution
s 至少比 uniform_int_distribution
慢 2 倍和 6 倍以上 ,尽管它们给出了相同的结果。
我希望 bernoulii_distribition
表现更好,因为它是专门为只有两种结果的概率而设计的,真或假;然而,它没有。
鉴于以上和以下性能指标,伯努利分布在 uniform_int_distributions 上是否有实际用途?
5 次运行的结果(发布模式,x64 位): (有关未附加调试器的发布运行,请参阅下面的编辑)
bernoulli: 58 ms
false: 500690
true: 499310
uniform: 9 ms
1: 499710
0: 500290
----------
bernoulli: 57 ms
false: 500921
true: 499079
uniform: 9 ms
0: 499614
1: 500386
----------
bernoulli: 61 ms
false: 500440
true: 499560
uniform: 9 ms
0: 499575
1: 500425
----------
bernoulli: 59 ms
true: 498798
false: 501202
uniform: 9 ms
1: 499485
0: 500515
----------
bernoulli: 58 ms
true: 500777
false: 499223
uniform: 9 ms
0: 500450
1: 499550
----------
分析代码:
#include <chrono>
#include <random>
#include <iostream>
#include <unordered_map>
int main() {
auto gb = std::mt19937{std::random_device{}()};
auto bd = std::bernoulli_distribution{};
auto bhist = std::unordered_map<bool, int>{};
auto start = std::chrono::steady_clock::now();
for(int i = 0; i < 1'000'000; ++i) {
bhist[bd(gb)]++;
}
auto end = std::chrono::steady_clock::now();
auto dif = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "bernoulli: " << dif.count() << " ms\n";
std::cout << std::boolalpha;
for(auto& b : bhist) {
std::cout << b.first << ": " << b.second << '\n';
}
std::cout << std::noboolalpha;
std::cout << '\n';
auto gu = std::mt19937{std::random_device{}()};
auto u = std::uniform_int_distribution<int>{0, 1};
auto uhist = std::unordered_map<int, int>{};
start = std::chrono::steady_clock::now();
for(int i = 0; i < 1'000'000; ++i) {
uhist[u(gu)]++;
}
end = std::chrono::steady_clock::now();
dif = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "uniform: " << dif.count() << " ms\n";
for(auto& b : uhist) {
std::cout << b.first << ": " << b.second << '\n';
}
std::cout << '\n';
}
编辑
我重新运行 没有附加调试符号的测试,bernoulli 仍然 运行 慢了 4 倍:
bernoulli: 37 ms
false: 500250
true: 499750
uniform: 9 ms
0: 500433
1: 499567
-----
bernoulli: 36 ms
false: 500595
true: 499405
uniform: 9 ms
0: 499061
1: 500939
-----
bernoulli: 36 ms
false: 500988
true: 499012
uniform: 8 ms
0: 499596
1: 500404
-----
bernoulli: 36 ms
true: 500425
false: 499575
uniform: 8 ms
0: 499974
1: 500026
-----
bernoulli: 36 ms
false: 500847
true: 499153
uniform: 8 ms
0: 500082
1: 499918
-----
class bernoulli_distribution
用于生成可能不均匀比率的布尔值。为此,它必须在 [0,1] 范围内生成一个浮点数,然后将其与给定概率进行比较。或任何等价物。
很明显,此例程可能比采用随机整数模 2 慢 - 这几乎是从随机数在 {0,1}
中创建统一数所需的全部。
有什么好惊讶的?只有当编译器在编译期间知道它是 50/50 的同时以某种方式设法找出不必要的操作时,性能才能达到偶数。
默认构建的 std::bernoulli_distribution
对两种结果赋予相同的权重,但您可以为其赋予不同的分布参数以更改概率。这可能会导致额外的复杂性。更好的比较是使用 std::uniform_real_distribution<double>
并将其结果与 0.5 进行比较(默认情况下,它会给出 [0, 1)
范围内的随机数)。
See here 例如:
gcc 输出:
bernoulli: 28 ms
false: 499818
true: 500182
uniform: 31 ms
1: 500686
0: 499314
real: 29 ms
1: 500191
0: 499809
clang 输出:
bernoulli: 106 ms
false: 500662
true: 499338
uniform: 23 ms
1: 501263
0: 498737
real: 101 ms
1: 499683
0: 500317
使用 gcc 的结果大致相同(多次运行往往会给 uniform int 更长的时间,这与您看到的相反)。随着 clang 我得到 bernoulli 和 real 大致相同,而 uniform int 的时间要少得多。这两个都使用 -O3
.
一些评论和答案建议改用 uniform_real_distribution
。
我测试了 uniform_real_distribution(0.0f, nextafter(1.0f, 20.f))
(考虑到 urd
是半封闭范围)与 bernoulli_distribution
相比 bernoulli_distribution
快了大约 20%-25%不管概率如何(并给出 更正确的结果 。我测试了 1.0
真实概率,而我使用上述 urd
值的实现实际上给出了假阴性(授予一个或 5 次一百万次运行中的两次)并且 bernoulli
给出了正确的 none.
因此,速度方面:bernoulli_distribution
比 uniform_real_distribution
快但比 uniform_int_distribution
慢。
长话短说,使用正确的工具来完成工作,不要重新发明轮子,STL 构建良好等等,取决于用例,一个比另一个更好。
对于是-否概率(IsPercentChance(float probability)
),bernoulli_distribution
更快更好。
对于纯粹的“给我一个随机的随机布尔值”,uniform_int_distribution
更快更好。