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 随机数函数 学习之一:产生服从均匀分布随机数

  • 相关阅读:
    使用bootstrap中的toolTip插件时 最上方提示会被遮挡问题
    Vue中splice的使用
    由于eslint语法检查工具限制很严格,导致启动项目是报错的解决办吧(使用cmder工具时发生的错误)
    windows命令行工具—Cmder配置
    mui触发自定义事件(子页面返回传递给父级页面值)
    计算最长英语单词链
    周总结14
    找水王
    用户体验评价
    周总结13
  • 原文地址:https://www.cnblogs.com/zztt/p/4025207.html
Copyright © 2011-2022 走看看