C ++ 11类< random>的分布如何?转换基础生成器? [英] How do distributions of C++11 class <random> transform the underlying generator?

查看:72
本文介绍了C ++ 11类< random>的分布如何?转换基础生成器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码似乎不直观:

#include <random>
#include <iostream>
using namespace std;

int main()
{

  mt19937 MyGenerator(40);
  auto gauss = normal_distribution<double>(0,1);
  auto linear = uniform_real_distribution<double>(0,1);
  cout << gauss(MyGenerator) << endl; //line a
  cout << linear(MyGenerator) << endl; //line b
  cout << gauss(MyGenerator) << endl;
}

运行此代码将给出输出

-0.816097
 0.705030
 0.303032.

如果现在交换了行a和b的顺序,则输出将更改为

If now the order of lines a and b is swapped, the output changes to

 0.644008
 0.338080
-0.639501.

很明显,前两个数字现在不同,因为它们是由不同的分布产生的.但是,为什么第三个数字不同? 根据我的直觉,分布应获取一个数字c = MyGenerator(),然后将其映射到特定范围内的随机数.随机数生成器将在分配调用之后指向数字序列中的下一个数字.因此,在这两种情况下,第三次致电的结果不应该相同吗?

It is completely clear that the first two numbers are different now, as they are produced by different distributions. Nevertheless, why is the third number different? In my intuition, the distribution should grab a number c = MyGenerator() which is then mapped to the random number in the specific range. The random number generator would point to the next number in the sequence of numbers after the distribution call. So, shouldn't the outcome of the third call be the same in both cases?

另一个观察结果: 实际上,向两个分布中的任何一个添加第四调用似乎都可以重现相同的数字.

Another observation: Adding a forth call to either of the distributions does in fact seem to reproduce the same numbers.

推荐答案

libstdc ++的normal_distribution实现使用 Marsaglia极坐标法.这种方法的有趣之处在于,每次通过都使用来自URNG的两个随机数来生成两个结果.

libstdc++'s implementation of normal_distribution uses the Marsaglia polar method. The interesting thing about this method is that each pass uses two random numbers from the URNG to generate two results.

也就是说,对分布的第一次调用会两次调用URNG(可能会多次,因为它使用拒绝采样,但是次数是偶数),并返回一个结果;以下对发行版的调用不会调用URNG,但会返回保存的第二个结果.

That is, the first call to the distribution calls the URNG twice (possibly more times, as it uses rejection sampling, but an even number of times) and returns one result; the following call to the distribution will not call the URNG but will return the saved second result.

这是从源代码中提取的,重新格式化:

if (_M_saved_available)
{
    _M_saved_available = false;
    ret = _M_saved;
}
else
{
    result_type x, y, r2;
    do
    {
        x = result_type(2.0) * aurng() - 1.0;
        y = result_type(2.0) * aurng() - 1.0;
        r2 = x * x + y * y;
    }
    while (r2 > 1.0 || r2 == 0.0);

    const result_type mult = std::sqrt(-2 * std::log(r2) / r2);
    _M_saved = x * mult;
    _M_saved_available = true;
    ret = y * mult;
}

这篇关于C ++ 11类&lt; random&gt;的分布如何?转换基础生成器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆