:根据几率取随机数的php算法

无心间看回一年前(2009-2-10)在ppc和houlai、youd讨论关于“根据几率取随机数”算法。问题是这样的:php

houlai:设随机抽到A的几率为0.1,B的几率为0.2,C的几率为0.3,D的几率为0.4,如今求按此几率随机抽出一个字母的算法算法

当时本身刚学了几率论,因此没有采用网上常见的“利用数组初始化,而后依据几率填充内容,再而后打乱该数组,最后再依据某个规则取数组内某个值”(事实上也会把内存给耗光),而改成另一种方法:数组

horseluke:把1——100当作是一条线段。而后几率就是用于切割这条线条的,咱们要作的其实只须要随机产生一个数,而后看这个数对应于哪一条分线条就OK了。这样,数组不需太大,并且还能获得一样的效果。函数

举个例子,A字母为30%几率,B字母为70%几率。那么能够把这条0——100的线段分割为2段。
一段为0——30,为A字母;其他的分属B字段
好了,程序如今随机抽取了30这个数,那么很明显,结果就是A了。
测试

|-----------|-----------------------|
0           30                     100
spa

但是接下来写的实现代码,如今看来可真是乱七八糟的。后来youd提出了一个更好的算法并写出了php代码,让本身汗颜不已:orm

youd:开始是从1,1000这个几率范围内筛选第一个数是否在他的出现几率范围 以内,若是不在,则将几率空间,也就是k的值减去刚刚的那个数字的几率空间,在本例当中就是减去100,也就是说第二个数是在1,900这个范围内筛选 的。我想应该很容易理解,这样筛选到最终,总会有一个数知足要求(好比说前三个都不幸成为了非Luck Num,那么k已经-100-200-300=400了,那么最后一个数不管如何也会知足要求的。至关于拿东西,第一个不是,第二个不是,第三个还不是, 那最后一个必定是。内存

这个算法的优势是,对于没有几率重叠的数字进行筛选,最多只须要遍览一次数组就足够了。程序简单,效率高get

一年后看回此贴,真是感慨本身当初写PHP代码的幼稚(固然,如今其实水平也很菜)。趁着如今写论文的休息时间,把youd的算法用函数给包装起来,以待之后使用。it

不知道当年一块儿讨论的人,如今如何了......

代码以下:

<?php

function pro_rand( $proArr ){
    $result = '';

    //几率数组的总几率精度
    $proSum = array_sum($proArr);
   
   
    foreach ( $proArr as $key => $proCur ){
        $randNum = mt_rand(1, $proSum);
        if( $randNum <= $proCur ){
            $result = $key;
            break;
        }else{
            $proSum -= $proCur;
        }
    }
   
    return $result;
   
}



function pro_rand_unique_multi( $proArr, $num = 1 ){
    $result = array();
    if( $num > count($proArr) ){
        trigger_error('The stack number of Probability Array is GREATER THAN you set!', 256);
    }
   
    while(1){
        if($num < 1){
            break;
        }
        $curResult = pro_rand($proArr);
        $result[] = $curResult;
        //重置总几率精度,有待几率论验证
        unset($proArr[$curResult]);
        $num -= 1;
    }
   
    return $result;
   
}

  

以上函数的测试代码:

pro_rand:

$proArr = array(10,20,30,40);
mt_srand(time());

$distribute = array();
for($k = 1; $k <= 1000; $k++ ){

    $result = pro_rand($proArr);
    if(!isset($distribute[$result])){
        $distribute[$result] = 1;
    }else{
        $distribute[$result] += 1;
    }

}

ksort($distribute);
var_export($distribute);

pro_rand_unique_multi:

$proArr = array(10,20,30,40);
mt_srand(time());

$distribute = array();
for($k = 1; $k <= 1000; $k++ ){

    $result = pro_rand_unique_multi($proArr, 2);
    foreach($result as $key => $proKey){
        if(!isset($distribute[$proKey])){
            $distribute[$proKey] = 1;
        }else{
            $distribute[$proKey] += 1;
        }
    }

}

ksort($distribute);
var_export($distribute);

(完)

相关文章
相关标签/搜索