首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >bernoulli_distribution对uniform_int_distribution

bernoulli_distribution对uniform_int_distribution
EN

Stack Overflow用户
提问于 2021-04-14 19:35:53
回答 3查看 234关注 0票数 1

在比较bernoulli_distribution的默认构造函数(50/50的真/假概率)和uniform_int_distribution{0, 1} (一致的概率为0或1)时,我发现bernoulli_distributions至少比uniform_int_distribution慢2倍和6倍以上,尽管它们给出了相同的结果。

我希望bernoulii_distribition能够更好地执行,因为它是专门为两个结果的概率而设计的,是正确的还是错误的;然而,它没有。

鉴于以上和下面的性能指标,伯努利发行版在uniform_int_distributions?上有实际用途吗?

结果超过5次运行(发布模式,x64位):(在没有附加调试器的情况下,请参阅下面的版本运行编辑)

代码语言:javascript
复制
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
----------

剖析代码:

代码语言:javascript
复制
#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倍的速度:

代码语言:javascript
复制
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
-----
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-04-16 02:26:13

一些评论和回答建议使用uniform_real_distribution

我测试了uniform_real_distribution(0.0f, nextafter(1.0f, 20.f)) (说明urd是半封闭的范围)和bernoulli_distribution,不管概率如何,bernoulli_distribution的速度大约是20%-25% (并且给出了更正确的结果。我测试了1.0的真实概率,我使用上述urd值的实现实际上给出了假否定(五百万次运行中有一次或两次),而bernoulli给出了正确的一次。

所以,就速度而言:bernoulli_distributionuniform_real_distribution快,但比uniform_int_distribution慢.

长话短说,对工作使用正确的工具,不要重新发明轮子,STL是构建良好的等等,并且取决于用例一个比另一个更好。

是的-不可能(IsPercentChance(float probability)),bernoulli_distribution更快更好。

对于纯粹的“给我一个随机的布尔值”,uniform_int_distribution更快更好。

票数 0
EN

Stack Overflow用户

发布于 2021-04-14 19:54:06

默认构造的std::bernoulli_distribution对这两种结果的权重相等,但您可以给它一个不同的分布参数来更改概率。这可能会带来额外的复杂性。更好的比较方法是使用std::uniform_real_distribution<double>并将其结果与0.5进行比较(默认情况下,它在[0, 1)范围内给出一个随机数)。

例如,看这里

gcc产出:

代码语言:javascript
复制
bernoulli: 28 ms
false: 499818
true: 500182

uniform: 31 ms
1: 500686
0: 499314

real: 29 ms
1: 500191
0: 499809

clang输出:

代码语言:javascript
复制
bernoulli: 106 ms
false: 500662
true: 499338

uniform: 23 ms
1: 501263
0: 498737

real: 101 ms
1: 499683
0: 500317

使用gcc的结果大致相同(多次跑会给出更高的时间,这与你所看到的完全相反)。有了clang,我就得到了bernoulli和real的相似之处,而制服int的时间要少得多。这两种方法都使用-O3

票数 2
EN

Stack Overflow用户

发布于 2021-04-14 19:52:43

bernoulli_distribution用于生成具有可能不均匀比率的布尔值。为了达到这个目的,它必须在0,1范围内生成一个浮点,然后将它与给定的概率进行比较。或者任何类似的东西。

很明显,这个例程可能比随机整数模2慢--这几乎是从随机数在{0,1}中创建一个统一数所需的全部。

这怎么会令人惊讶?只有当编译器设法找出不必要的操作,同时意识到编译时是50/50时,性能才能达到平衡。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67098054

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档