我正在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
中相应元素的正负单位一致。但是,我没有做进一步的事情:我检查了天花板,地板,固定和倒圆角,但是它们似乎都没有作用。
答案 0 :(得分:2)
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)
)或类似上述的下限划分法,但请删除会使分布偏斜的一小部分值。 This other anser进行了详细说明。我喜欢从示例的角度来思考它:
说随机值在[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
的序列可能适合数百万个数字,但随后开始偏离。
有趣的是,Octave的randi
被实现为M文件,因此我们可以看到它们是如何实现的。事实证明,它基于rand
使用了该答案顶部显示的错误算法:
ri = imin + floor ( (imax-imin+1)*rand (varargin{:}) );
因此,八度的randi
有偏见!