本节主要受到《编程珠玑》第12章随机取样问题的启发,但不仅仅限于随机取样问题,进一步地,研究讨论了一些在笔试面试中常见的和随机函数以及概率相关的问题。
阅读本文所需的知识:
1.对C语言中或其他语言中等价的rand()、srand()有所了解。本文不讨论种子的设定和伪随机数的问题;
2.中学或以上水平的概率基本概念。
目录
“珠玑之椟”系列简介与索引
问题1(《编程珠玑》习题12.1后半段):
给定一个rand(),可以产生从0到RAND_MAX的随机数,其中RAND_MAX很大(常见值:16位int能表示的最大整数32767),写出利用rand()生成[a,b]中任意整数的函数,其中a>=0, b<=RAND_MAX,且b-a<<RAND_MAX.
分析:
这是在编程工作最常见的随机函数的应用,在这里做一个起点再合适不过。把随机数区间的起点从0变为a,同时把一共RAND_MAX+1个数的区间缩小至只含有b-a+1个数的区间,写为 a + rand()%(b-a+1),此时显然最大值是a+(b-a)= b。
进一步地,这个b-a<<RAND_MAX的条件虽然看上去不起眼,其实很重要。
附加思考:
如果b-a和RAND_MAX很接近会发生什么情况?读者不妨先做思考,问题2的分析会做出解答。
这个rand(),其实相当于《编程珠玑》提到的bigrand()。
问题2(笔试题变形):
给定一个随机数函数rand7(),它能以等概率生成1~7这7个整数。请根据rand7()写出类似的rand5()。
分析:
如果直接像问题1中一样,把1+rand7()%5作为rand5()会有什么情况发生?这时确实能产生1~5的随机数没错,可是各个数的概率相等吗?
对于随机数2,既有可能来自于1+1%5,也有可能来自于1+6%5,显然其概率是2/7,而不是1/5,不满足rand5()等概率产生各随机数这一隐含要求。不同于问题1,问题1中一个很大的区间收缩成较小区间时,各个元素映射后的新元素概率虽然概率可能不完全一样,但却是近似相同的。
为了满足等概率的要求,可以这么做:
int rand5() { int res; do { res = rand7(); } while(t>=6); return res; }