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
смещена!