Какая связь между ранди и рандом? - PullRequest
0 голосов
/ 04 сентября 2018

Я работаю на версии R2012a. Я попытался написать функцию, которая имитирует randi, используя rand (только rand), производя такой же вывод, когда передаются одинаковые аргументы и предоставляется одинаковое начальное число. Я попробовал что-то с окном команд, и вот что я получил:

>> s = rng;
>> R1 = randi([2 20], 3, 5)

R1 =

     2    16    11    15    14
    10    17    10    16    14
     9     5    14     7     5

>> rng(s)
>> R2 = 2+18*rand(3, 5)

R2 =

    2.6200   15.7793   10.8158   14.7686   14.2346
    9.8974   16.3136   10.0206   15.5844   13.7918
    8.8681    5.3637   13.6336    6.9685    4.9270

>> 

Быстрое сравнение привело меня к мысли, что между ними есть какая-то связь: каждое целое число в R1 находится в пределах плюс или минус единица от соответствующего элемента в R2. Тем не менее, я не смог пойти дальше: я проверил потолок, полы, крепления и закругления, но ни один из них, похоже, не работает.

1 Ответ

0 голосов
/ 04 сентября 2018

randi([2 20]) генерирует целые числа от 2 до 20, оба включены. То есть он может генерировать 19 разных значений, а не 18.

19 * rand

генерирует значения, равномерно распределенные в полуоткрытом интервале [0,19), что дает вам равномерно распределенные целые числа в диапазоне [0,18].

Таким образом, в общем,

x = randi([a,b]]);
y = rand * (b-a+1) + a;

должно давать числа с одинаковым свойством. Из эксперимента OP похоже, что они могут генерировать одну и ту же последовательность, но это не может быть гарантировано, и, вероятно, нет.

Почему? Вполне вероятно, что randi не реализован в терминах rand, но это основной генератор случайных чисел, который производит целые числа. Чтобы перейти от случайного целого числа x в большом диапазоне ([0,N-1]) к одному в небольшом диапазоне ([0,n-1]), вы обычно используете оператор по модулю (mod(x,N)) или разделенное по этажам деление, как указано выше, но удалить небольшое подмножество значений, которые искажают распределение. Этот другой ансер дает подробное объяснение. Мне нравится думать об этом в терминах примеров:

Допустим, случайные значения находятся в диапазоне [0,2^16-1] (N=2^16), а вы хотите значения в диапазоне [0,18] (n=19). mod(19,2^16)=5. То есть самые большие 5 значений, которые могут быть сгенерированы генератором случайных чисел, сопоставляются с самыми низкими 5 значениями выходного диапазона (при условии метода по модулю), в результате чего эти числа с большей вероятностью будут сгенерированы, чем остальная часть выходного диапазона , Эти 5 самых низких значений имеют шанс floor(N/n)+1, в то время как остальные имеют шанс floor(N/n). Это плохо. [Использование деления по этажам вместо модуля дает другое распределение неравномерности, но конечный результат тот же: некоторые числа немного более вероятны, чем другие.]

Чтобы решить эту проблему, правильная реализация делает следующее: если вы получаете одно из значений в генераторе случайных чисел floor(N/n)*n или выше, вам нужно выбросить его и повторить попытку. Конечно, это очень маленький шанс с типичным генератором случайных чисел, который использует N=2^64.

Хотя мы не знаем, как реализован randi, мы можем быть совершенно уверены, что он следует правильной реализации, описанной здесь. Таким образом, ваша последовательность, основанная на rand, может подходить для миллионов чисел, но затем начните отклоняться.


Интересно, что randi от Octave реализован в виде M-файла, поэтому мы можем видеть, как они это делают. И оказывается, что он использует неправильный алгоритм, показанный в верхней части этого ответа, основанный на rand:

 ri = imin + floor ( (imax-imin+1)*rand (varargin{:}) );

Таким образом, октава randi смещена!

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