Почему генератор псевдослучайных чисел с меньшей вероятностью сгенерирует 54 больших числа подряд? - PullRequest
8 голосов
/ 06 августа 2020

Рассмотрим событие, которое происходит с вероятностью p . Эта программа проверяет, сколько неудачных попыток требуется, прежде чем событие произойдет, и сохраняет гистограмму итоговых значений. например: Если бы p было 0,5, то это было бы похоже на вопрос , сколько раз подряд монета выпадет решкой, прежде чем выпадет решка ? При меньших значениях p , мы ожидаем много неудач, прежде чем добьемся успеха.

Тестируемая реализация по существу: while (!(rand.NextDouble() < p)) count++;

Вот график гистограмма результатов для count .

enter image description here

Immediately obvious is the irregularity at x=54. For some reason, it is approximately half as likely as it should be for a series of exactly 54 random numbers greater than or equal to p to be generated in a row.

The actual p I'm checking in this test is 1/32. (Doesn't really matter, as long as it's small enough to get some measurable number of 54's as an outcome.) And I'm counting 10000000 total successes. (Also doesn't seem to matter.) It also doesn't matter what random seed I use.

Obviously this is a quirk of the pseudo-random number generator being used by the Random.NextDouble function in .NET. But I'd like to know why does this otherwise uniform data have such a striking single spike in such an oddly specific and consistent place? What is it about this particular pseudo-random number generator that makes generating exactly 54 large numbers in a row followed by a small number half as likely as any other sequence length?

I would have expected many more non-uniform anomalies as it degenerates, not just this one spike.


Here is the code that generated this data set:

using System;

namespace RandomTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rand = new Random(1);
            int numTrials = 10000000;
            int[] hist = new int[512];
            double p = 1.0 / 32.0;
            for (int i = 0; i < numTrials; ++i) {
                int count = 0;
                while (!(rand.NextDouble() < p)) {
                    count++;
                }
                if (count > hist.Length - 1) {
                    count = hist.Length - 1;
                }
                hist[count]++;
            }
            for (int i = 0; i < hist.Length; ++i) {
                Console.WriteLine("{0},{1}", i, hist[i]);
            }
        }
    }
}

Если это актуально, это. Net Framework 4.7.2 на Windows x86.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...