获取任意概率函数
举个例子,有一枚硬币,抛出后正面朝上的概率为$q$,这个问题等价于如何通过多次抛一枚硬币获取概率为$p$的事件。
事实上,可以多次组合抛硬币事件来实现。下面我们的任务是组合多个事件让它们的概率之和等于$p$。设最终求出的事件为S,在此做个规定,S包括或包括于第一次正面向上衍生的事件。
第一次抛,正面向上的概率是$q$,反面朝上的概率是$1-q$。
如果$p\leq q$,则S应该包括于第一次正面向上衍生的事件。
如果抛出正面朝上,接下来在第一次正面向上衍生的事件中寻找概率和为$p$的事件即可,相当于从第一次开始抛硬币,找出概率为$\frac{p}{q}$的事件,这是因为
所以$S\cap{第一次正面向上衍生的事件}=S$。
在反面朝上发生的情况下,由于S是包括于第一次正面向上衍生的事件的,所以反面朝上衍生的事件不可能和S有交集,因此返回False。
如果$p>q$,则S应该包括第一次正面向上衍生的事件。
如果正面朝上直接返回True即可;
在反面的情况下,需要在第一次反面朝上衍生的事件中寻找概率和为$p-q$的事件,相当于从零开始抛硬币,找出概率为$\frac{p-q}{1-q}$的事件族。
接下来递归即可。
上面的解释比较抽象,可以用数形结合的方式:
我们的目的是要求一个数确定性地落在$[0,p]$区间,现在只知道这个数是不是落在$[0,q]$区间。
- 情况1:$p>q$。如果第一次就落在了$[0,q]$区间,肯定满足落在$[0,p]$区间的要求,直接返回true;如果落在$[q,1]$区间,需要确保它落在[q,p]区间,此时将[q,1]放缩到[0,1],[q,p]放缩为$[0,\frac{p-q}{1-q}]$,相当于重新抛硬币获取概率为$\frac{p-q}{1-q}$的事件。
- 情况2:$p<q$。如果第一次就落在了$[q,1]$区间,肯定不满足落在$[0,p]$区间的要求,直接返回false;如果落在$[0,q]$区间,需要确保它落在[0,p]区间,此时将[0,q]放缩到[0,1],[0,p]放缩为$[0,\frac{p}{q}]$,相当于重新抛硬币获取概率为$\frac{p}{q}$的事件。
测试代码:
1 | import random |
拓展:
470. 用 Rand7() 实现 Rand10() - 力扣(LeetCode)
思路:这道题可以用Rand7()生成等概率的49个数,然后划分出相等的10个区间,用拒绝采样策略舍弃掉剩余的区间。不过这种题其实有通解,如下:
1 | # The rand7() API is already defined for you. |