zoukankan      html  css  js  c++  java
  • Javascript 随机数函数 学习之二:产生服从正态分布随机数

    一、为什么需要服从正态分布的随机函数

    一般我们经常使用的随机数函数 Math.random() 产生的是服从均匀分布的随机数,能够模拟等概率出现的情况,例如 扔一个骰子,1到6点的概率应该相等,但现实生活中更多的随机现象是符合正态分布的,例如20岁成年人的体重分布等。

    假如我们在制作一个游戏,要随机设定许许多多 NPC 的身高,如果还用Math.random(),生成从140 到 220 之间的数字,就会发现每个身高段的人数是一样多的,这是比较无趣的,这样的世界也与我们习惯不同,现实应该是特别高和特别矮的都很少,处于中间的人数最多,这就要求随机函数符合正态分布。

    二、正态分布复习

     

    图片来自:http://zh.wikipedia.org/zh-cn/%E6%AD%A3%E6%80%81%E5%88%86%E5%B8%83

    具体性质也请查阅上面链接,描述正态分布的主要特征是均值和方差,如上图,最左的倒钟形图的均值为-2, 其余为0 ;

    方差越大,钟形越扁平,方差越小越陡;

    • 密度函数图像关于均值对称。
    • 在x=μ±σ处,曲线有拐点。
    • 函数曲线下68.26%的面积在平均数左右的一个标准差σ的区间内。
    • 95.44%的面积在平均数左右两个标准差2σ的区间内。
    • 99.74%的面积在平均数左右三个标准差3σ的区间内。

    当均值为0, 方差为 1 时称为标准正态分布;

    三、由均匀分布经 “Box-Muller法” 转换为正态分布

    通过查阅文献可知(请参见:http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform),有一个称为 Box-Muller (1958) 转换的算法能够将两个在区间(0,1] 的均匀分布转化为标准正态分布,其公式为:

    y1 = sqrt( - 2 ln(u) ) cos( 2 pi v )

    y2 = sqrt( - 2 ln(u) ) sin( 2 pi v )

    因为三角函数计算较慢,我们可以通过上述公式的一个 polar form(极坐标形式)能够简化计算,

    算法描述如下:

    function getNumberInNormalDistribution(mean,std_dev){
        return mean+(randomNormalDistribution()*std_dev);
    }
    
    function randomNormalDistribution(){
        var u=0.0, v=0.0, w=0.0, c=0.0;
        do{
            //获得两个(-1,1)的独立随机变量
            u=Math.random()*2-1.0;
            v=Math.random()*2-1.0;
            w=u*u+v*v;
        }while(w==0.0||w>=1.0)
        //这里就是 Box-Muller转换
        c=Math.sqrt((-2*Math.log(w))/w);
        //返回2个标准正态分布的随机数,封装进一个数组返回
        //当然,因为这个函数运行较快,也可以扔掉一个
        //return [u*c,v*c];
        return u*c;
    }

    因此,假如我们要获得均值为180,要68.26%左右的NPC身高都在[170,190]之内,即1个标准差范围内,因此标准差为10, 可以通过getNumberInNormalDistribution(180,10) 调用,我们实验1000000词,得到结果如下:

    // 身高:频率
    128:1
    132:1
    133:1
    134:1
    135:1
    136:2
    137:4
    138:8
    139:11
    140:14
    141:19
    142:28
    143:41
    144:54
    145:80
    146:133
    147:153
    148:235
    149:333
    150:429
    151:598
    152:764
    153:1059
    154:1314
    155:1776
    156:2290
    157:2835
    158:3503
    159:4373
    160:5513
    161:6475
    162:7809
    163:9437
    164:11189
    165:13282
    166:15020
    167:17239
    168:19215
    169:21597
    170:24336
    171:26684
    172:29000
    173:31413
    174:33179
    175:35027
    176:37084
    177:38047
    178:38968
    179:39635
    180:39700
    181:39548
    182:38960
    183:38674
    184:36948
    185:35220
    186:33224
    187:31038
    188:29198
    189:26668
    190:23893
    191:21662
    192:19476
    193:16898
    194:15056
    195:13046
    196:10971
    197:9456
    198:7928
    199:6697
    200:5370
    201:4334
    202:3548
    203:2810
    204:2330
    205:1765
    206:1350
    207:1093
    208:797
    209:595
    210:371
    211:328
    212:255
    213:165
    214:121
    215:91
    216:71
    217:29
    218:32
    219:28
    220:20
    221:6
    222:7
    223:7
    224:3
    225:2
    228:1

    绘制成柱状图如下:

    可见,这是有着非常明显的正态分布图像特征。

    四、由均匀分布叠加获得正态分布

    我们需要祭出万能的中心极限定理。

    根据独立同分布的中心极限定理:设随机变量X1,X2,...Xn,...相互独立,服从同一分布,且数学期望为μ,标准差为σ (σ>0),则随机变量之和的标准化变量:

    Y=((X1+X2+...+Xn)-nμ)/(sqrt(n)*sqrt(σ)) 近似服从标准正态分布 N(0,1)

    如果我们将足够多个均匀分布随机变量相加,相加之和将服从正态分布。但是,我们需要累加多少个均匀分布才能较好低近似正态分布呢?

    由于 X~U(0, 1) , 可得 μ=1/2, σ=sqrt(1/12),代入上面的式子即可近似模拟随机变量之和的概率密度函数(p.d.f).

    下图是由2个服从 U(0,1) 分布的随机变量相加得到的 p.d.f 图像:

     

    如果我们增加累加的均匀分布的数量会怎样呢?

    上图是 n=3 时的图像,可以看到正态分布的形状出来了,但顶端还略为平缓。

     

    特别低,当n=12时 (随机变量(X1+X2+...+Xn)的均值为6,方差为1)  这时有一个很好的特点,公式 Y=((X1+X2+...+Xn)-nμ)/(sqrt(n)*sqrt(σ)) 的分母正好为1,因此简化成了 Y=((X1+X2+...+Xn)-nμ),非常便于编程计算,并且已经非常接近于标准正态分布,请见下图:

    也就是说均值为μ,标准差为σ 的独立同分布变量 X1,X2, ..., Xn 的算数平均数  T=(X1+X2+ ...+ Xn)/n,当n充分大时,近似地服从均值为μ,方差为σ*σ/n 的正态分布。

    最后,代码如下:

    function getNumberInNormalDistribution(mean,std_dev){    
        return mean+(uniform2NormalDistribution()*std_dev);
    }
    
    function uniform2NormalDistribution(){
        var sum=0.0;
        for(var i=0; i<12; i++){
            sum=sum+Math.random();
        }
        return sum-6.0;
    }

    同样,将产生100万个随机数按频率画出直方图如下:

    如何产生服从均匀分布的随机数呢?

    请见上篇:

    Javascript 随机数函数 学习之一:产生服从均匀分布随机数

  • 相关阅读:
    HDU 1501 Zipper(DFS)
    HDU 2181 哈密顿绕行世界问题(DFS)
    HDU 1254 推箱子(BFS)
    HDU 1045 Fire Net (DFS)
    HDU 2212 DFS
    HDU 1241Oil Deposits (DFS)
    HDU 1312 Red and Black (DFS)
    HDU 1010 Tempter of the Bone(DFS+奇偶剪枝)
    HDU 1022 Train Problem I(栈)
    HDU 1008 u Calculate e
  • 原文地址:https://www.cnblogs.com/zztt/p/4025207.html
Copyright © 2011-2022 走看看