【问题标题】:C++11 random numbers and std::bind interact in unexpected wayC++11 随机数和 std::bind 以意想不到的方式交互
【发布时间】:2012-12-11 00:36:36
【问题描述】:

我正在使用 GCC 4.6.3 并尝试使用以下代码生成随机数:

#include <random>
#include <functional>

int main()
{
    std::mt19937 rng_engine;

    printf("With bind\n");
    for(int i = 0; i < 5; ++i) {
        std::uniform_real_distribution<double> dist(0.0, 1.0);
        auto rng = std::bind(dist, rng_engine);
        printf("%g\n", rng());
    }

    printf("Without bind\n");
    for(int i = 0; i < 5; ++i) {
        std::uniform_real_distribution<double> dist(0.0, 1.0);
        printf("%g\n", dist(rng_engine));
    }

    return 0;
}

我希望这两种方法都能生成一个由 5 个随机数组成的序列。相反,这是我实际得到的:

With bind
0.135477
0.135477
0.135477
0.135477
0.135477
Without bind
0.135477
0.835009
0.968868
0.221034
0.308167

这是 GCC 错误吗?还是与 std::bind 有关的一些微妙问题?如果是这样,你能理解结果吗?

谢谢。

【问题讨论】:

    标签: c++ gcc random c++11 stdbind


    【解决方案1】:

    绑定时,会生成 rng_engine 的副本。如果你想传递一个参考,这就是你必须做的:

    auto rng = std::bind(dist, std::ref(rng_engine));
    

    【讨论】:

    • 不公平,我在发布速度 +1 之前接到了妈妈的电话。
    • 该死,我不能只用笑脸回答 :)
    • 有点跑题了,但是如果你想使用 bind 并通过引用每个 std::thread 来传递一个生成器呢?
    • 如果你通过引用不同的线程来传递生成器,你可能会遇到麻烦:由于生成器有一个内部状态,你会遇到并发问题。因此互斥和头痛。为每个线程提供自己的生成器(使用不同的种子)会更安全
    • 啊!当然,有道理。我从 Wikipedia (en.wikipedia.org/wiki/C%2B%2B11) 和 cplusplus.com (cplusplus.com/reference/random) 看到了这种模式。如果有人知道如何纠正它,也可能值得在那里纠正。谢谢!
    【解决方案2】:

    std::uniform_real_distribution::operator() 采用 Generator &amp;,因此您必须使用 std::ref 进行绑定

    #include <random>
    #include <functional>
    
    int main()
    {
        std::mt19937 rng_engine;
    
        printf("With bind\n");
        for(int i = 0; i < 5; ++i) {
            std::uniform_real_distribution<double> dist(0.0, 1.0);
            auto rng = std::bind(dist, std::ref(rng_engine));
            printf("%g\n", rng());
        }
    
        printf("Without bind\n");
        for(int i = 0; i < 5; ++i) {
            std::uniform_real_distribution<double> dist(0.0, 1.0);
            printf("%g\n", dist(rng_engine));
        }
    }
    

    【讨论】:

      【解决方案3】:

      bind() 用于重复使用。

      把它放在循环之外...

      std::mt19937 rng_engine;
      std::uniform_real_distribution<double> dist(0.0, 1.0);
      auto rng = std::bind(dist, rng_engine);
      
      for(int i = 0; i < 5; ++i) {
          printf("%g\n", rng());
      }
      

      ... 给了我预期的结果:

      0.135477
      0.835009
      0.968868
      0.221034
      0.308167
      

      【讨论】:

        猜你喜欢
        • 2012-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-10
        相关资源
        最近更新 更多