人工干预随机数中的概率and一些数组的小事

今天在群里丢了一把脸,起因是因为我在研究js里的随机数,前提是我不知道Math.random()会返回0,但是不会返回1,结果被人笑话了,这里拿出来,希望大家也注意这个基础的问题。

前几天在公交车上挤车,车上没有美女,于是我就开始想一些js问题,突然我想能不能人工控制js中的随机数的随机概率呢?在某些游戏中,我们故意控制概率来让洗出来的牌更加合理(我们那有种牌叫做保皇,每次地主和狗腿子都到了一个人家里的时候,那个人的牌一般都会特别好,我觉得这是人为设计的)。

说干就干,基本目标就是,给出一个数组,我可以设定其中某个元素被抽中的概率是某个值,之后随机从数组取值的时候会按照这个概率去取,而且可以多个设置。

先上代码吧,这是一个对象:(M和M.Array对象是我框架里的,不是原生对象)
view source
print?
01    var Random=function(arr_data){
02           this.array=arr_data;
03           this.probs=[];
04           this.refer_array=new Array();
05       }
06       Random.prototype={
07           /**
08            * 设置某个元素被抽中的几率
09            * @param {number} index 要设置的数组元素的索引
10            * @param {number} prob 概率,用0.**的方式表示,也可以设置0.0**,但是会增大计算量,也更精确
11            */
12           setProb:function(index,prob){
13               this.probs.push({index:index,prob:prob})
14           },
15           /**
16            * 在调用setProb之后调用,初始化数据,之后才可以开始取值
17            */
18           init:function(){
19               var count=0;
20               var prob_arr=[];
21               for(var i in this.probs){
22                   prob_arr.push(this.probs[i].index)
23                   for(var m=0;m<this.probs[i].prob*100;m++){
24                       this.refer_array.push(this.probs[i].index);
25                       count++;
26                   }
27               }
28               for(var i=count;i<100;i++){
29                   var m;
30                   while(M.Array.has(prob_arr,(m=Math.floor(Math.random()*this.array.length)))){
31                       continue;
32                   }
33                   this.refer_array.push(m)
34               }
35               
36           },
37          /**
38           * 随机取一个
39           */
40           getOne:function(){
41               var i=Math.floor(Math.random()*100);
42               return this.array[this.refer_array[i]];
43           }
44       }
45       var rand=new Random([1,2,3,4,5,6,7,8,9,0]);
46       rand.setProb(1, 0.8)
47       rand.setProb(2,0.1)
48       rand.init();
49       var result_arr=[]//取10000次,统计是否2出现了8000次,3是否出现1000次
50       for(var i=10000;i>0;i--){
51           result_arr.push(rand.getOne())
52       }
53       alert(M.Array.count(result_arr,2));//8000左右
54       alert(M.Array.count(result_arr,3));//1000左右

上面的程序里我定义了一个Random对象,然后实例化了一个rand,测试了一下,设置2出现的概率是0.8,3出现的概率是0.1.

之后得出结果,10000次中2出现的次数总是在8000左右,3出现的次数一直在1000左右.说明程序成功;

原理是什么呢?

这个程序的概率只能精确到100分之一,可以修改一下支持1000分之一等更高分辨率的概率.

在程序里我建立了一个100个元素的参考数组,开始设为空,之后我调用setProb的时候把特殊的设置保存在了this.probs里面,

之后我开始根据this.probs里的数据构建refer_arr这个参考数组,首先我读取了第一个设置概率的元素,把它的概率0.8乘以100 之后得到一个数80,然后把这个元素的索引向参考数组里填充80次,同理再把下一个概率0.1乘以100之后得到一个数10,之后向数组填充10个当前元素的索引,然后再随机在剩余的索引中取10次填充到参考数组里,这时候参考数组就有100个元素了,其中80个值为1,10个值为2,其他是随机的.

然后从这个参考数组里随机取一个元素,取到1的概率就是0.8啦,把这个索引在原来数组中的值返回,就是2啦,2出现的概率是0.8.

就是这样,结果经过测试,数据越多越精确.

这个东西就到这里吧,有兴趣的可以自己去探索,我这个方法虽然能出来结果,但是不一定是最好的方法,慎用!

下面说点数组的小事情:

最近在写框架玩,里面涉及到一些对数组的常用操作,开始我乱写,用prototype扩展了Array.后来发现用for遍历数组的时候,遍历里包含了我自定义的扩展方法,汗啊,终于知道为什么前辈们都说不能这样扩展了,大家一定要注意,千万不要再js里随意扩展原生对象,否则会跟别的程序或者库冲突.

之后我把对数组的操作都抽象出来,合到一个单例对象里了,在这里贴出来吧:
view source
print?
01    M.Array=function(){
02           return {
03               /**
04                *判断某个元素是否存在于数组中,是返回true,否返回false
05                *@param {array} arr 要处理的数组
06                *@param {object} item 元素
07                */
08               has:function(arr,item){
09                   for(var i in arr){
10                       if(arr[i]==item) return true;
11                   }
12                   return false;
13               },
14               /**
15                *从数组中移除某个元素
16                *@param {array} arr 要处理的数组
17                *@param {object} item 要移除的元素,注意不是索引
18                */
19               remove:function(arr,item){
20                   var j=arr.length;
21                   for(var i=0;i<j;i++){
22                       if(arr[i]==item){
23                           arr.splice(i, 1);
24                           j--;
25                       }
26                   }
27               },
28               /**
29                *对数组中的元素都执行一次func,最后返回处理后的结果
30                *
31                */
32               each:function(arr,func){
33                   for(var i in arr){
34                       arr[i]=func(arr[i]);
35                   }
36                   return arr;
37               },
38               /**
39                * 将数组打乱,原理是随机交换两个元素的值,可以设定洗牌次数
40                * @param {array} arr 要处理的数组
41                * @param {number} times 洗牌次数,如果不存在就按数组长度计算
42                */
43               random:function(arr,times){
44                   var arr_length=arr.length,index_1,index_2;
45                   times=times||arr_length;
46     
47                   for(var i=0;i<times;i++){
48                       index_1=Math.floor(Math.random()*arr_length)
49                       while((index_2=Math.floor(Math.random()*arr_length))==index_1){
50                           continue;
51                       }
52                       var temp=arr[index_1];
53                       arr[index_1]=arr[index_2]
54                       arr[index_2]=temp;
55                   }
56                   return arr;
57               },
58               toString:function(arr){
59                   var return_str="";
60                   for(var i in arr){
61                       return_str+=i+":"+arr[i]+"\n"
62                   }
63                   return return_str;
64               },
65               getMax:function(arr){
66                   var max=0;
67                   for(var i in arr){
68                       if(arr[i]*1>max) max=arr[i]*1
69                   }
70                   return max;
71               },
72               getMin:function(arr){
73                   var min=0;
74                   for(var i in arr){
75                       if(arr[i]*1<min) min=arr[i]*1
76                   }
77                   return min;
78               },
79               /**
80                * 统计数组中某个元素出现的次数
81                */
82               count:function(arr,item){
83                   var count=0;
84                   for(var i in arr){
85                       if(arr[i]==item){
86                           count++;
87                       }
88                   }
89                   return count;
90               }
91           }
92       }();

有哪里写的不好,希望大家多提提意见.

下面再说说数组的一些比较好玩的特性:

首先定义一个数组:
view source
print?
1    var arr1=[1,2,3,4,5,6,7,8,9,0]
alert 一下arr1.length结果是10,alert一下M.Array.toString(arr1) 这是刚才的对象里定义的方法会按照key:value的形式输出数组的所有值,结果输出:0:1 1:2 2:3 3:4 4:5 5:6 6:7 7:8 8:9 9:0

下面我们来设置一下 arr1.length=12看看数组会有什么变化:0:1 1:2 2:3 3:4 4:5 5:6 6:7 7:8 8:9 9:0 数组的值没有变,但是alert(arr1.length)竟然是12.其实这时候数组里有两个undefined的值,在遍历中体现不出来,但是在 length中体现出来了.

下面再操作一下:arr1.push(11);猜猜会输出什么?0:1 1:2 2:3 3:4 4:5 5:6 6:7 7:9 8:0 12:11,索引是从12开始的,虽然undefined的元素不能体现在遍历中,但是他们却的确占着一个数组的位置.

下面再设置一下:arr1.length=5;输出:0:1 1:2 2:3 3:4 4:5

是不是很灵活,由此可以用数组来做一些很灵活的操作,不过我就是觉得好玩,还不知道哪里能用到,这种特性在强类型语言里是绝对看不到的,js真是灵活的一比啊.

时间:2010年3月12日0:29:05,写完了,明天的周会就拿这篇文章来分享了.这几天忙,写个博客都静不下心来了,大家凑合看吧,不懂得或者有问题的可以加qq群:46532005交流.谢谢赏光哈,顺便点个推荐就更好了,哈哈
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值