1

I am using C++14. I want to generate a random number stream using a random engine and draw random variates from different distributions from this stream. I find, however, that there appears some interaction between the distributions which leads to unexpected behaviour. This is my code (compiled in MS Visual Studio 2019 with deafult compiler settings).

#include <random>
#include <iostream>
#include <vector>

int main()
{
    double alpha;
    std::cin >> alpha;
    std::default_random_engine generator;
    generator.seed(1);

    std::normal_distribution<> distNorm(0., 1.);
    std::gamma_distribution<> distGam(alpha, 1.);

    std::vector<double> normal;
    std::vector<double> gamma;

    for(size_t idxBatch = 0; idxBatch < 2; ++idxBatch)
    {
        for(size_t i = 0; i < 2; ++i)
            normal.push_back(distNorm(generator));

        for(size_t i = 0; i < 1; ++i)
            gamma.push_back(distGam(generator));
    }

    for(size_t i = 0; i < normal.size(); ++i)
        std::cout << normal[i] << std::endl;
    
    std::cout << std::endl;
    
    for(size_t i = 0; i < gamma.size(); ++i)
        std::cout << gamma[i] << std::endl;

    return 0;
}

Running the code with alpha = 1 produces:

-1.40287
-0.549746
0.188437
0.483496

0.490877
1.87282

Running the code with alpha = 2 produces:

-1.40287
-0.549746
-1.95939
0.257594

1.34784
2.28468

In other words, the output of the normal distribution is impacted by the parameter of the gamma distribution (3rd and 4th item in the first block)! This is unwanted. The normal distribution should be invariant against the parameterization of the gamma distribution.

Does anyone know what I am doing wrong?

bp236
  • 11
  • 2
  • 1
    distributions may request more bytes then needed from the generator in order to get an output with the correct probability. You might just want to have each distribution be backed by its own PRNG. – NathanOliver Aug 01 '22 at 13:30
  • [No reproduction in GCC12](https://godbolt.org/z/zf3ss5h9v). Please add your compiler, version and flags used. – Yksisarvinen Aug 01 '22 at 13:31
  • Thanks for your quick comments. I am using Visual Studio 2019 with standard compiler settings. Good point about the rejection sampling. Yes, using separate random engines removes the problem but that is not what I want since I am loosing the statistical properties of the underlying random number sequence. I was under the impression that using one single stream is in fact the recommended approach. The other alternative is to generate uniform numbers and create the required distribution using inversion. This might impact performance though. – bp236 Aug 01 '22 at 14:00
  • Thank you for the info about GCC12. This output looks what I would expect, i.e. same sequence of normals, different sequence of gammas. I am bound to VS though. – bp236 Aug 01 '22 at 14:06
  • Using a single engines is recommended if you don't need multiple, because the underlying PRNG may be somewhat predictable, especially at the start. But here you clearly do need multiple engines. Choose a good implementation rather than `default_random_engine` if you care about high-quality randomness, too. – Thomas Aug 01 '22 at 14:58
  • 1
    Use `\n` to end a line. There’s nothing here that requires the extra stuff that `std::endl` does. – Pete Becker Aug 02 '22 at 03:06

1 Answers1

6

The engine is the source of a stream of random bits. The distribution consumes these bits and turns them into numbers. A distribution may consume more or fewer bits for each number generated (e.g. if it uses rejection sampling). This explains why the output of one distribution is affected by the other.

If you want the output of the distributions to be independent, you should use two separate engines.

Thomas
  • 174,939
  • 50
  • 355
  • 478