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 随机数函数 学习之一:产生服从均匀分布随机数
Javascript 随机数函数 学习之二:产生服从正态分布随机数的更多相关文章
- Javascript 随机数函数 学习之一:产生服从均匀分布随机数
大家都知道Math.random是 javascript 中返回伪随机数的函数,但查看 MDN, The Math.random() function returns a floating-point ...
- 记JavaScript的入门学习(二)
2016年11月25号,利用上午时间学习了JavaScript的数据类型和变量,下午就该去图书馆泡书了. 看完变量的本章节,发现我可能不能一天结束,那我就利用上午和晚上九点回来的时间完成吧.把心态调整 ...
- SQL函数学习(二):DATEADD() 函数
DATEADD() 函数在日期中添加或减去指定的时间间隔. 语法 DATEADD(datepart,number,date) date 参数是合法的日期表达式.number 是您希望添加的间隔数:对于 ...
- JavaScript 原型链学习(二)原型的动态性
由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来,即使是先创建了实例后修改原型也照样如此.如下示例: var friend = new Person(); ...
- JavaScript零基础学习系列二
条件控制 if(条件){//语句块}如果条件(小括号里面的)满足true.那么才会执行大括号里面的代码,如果条件不满足(false),那么不执行,注意:有可能代码不会执行. 例如: if(3>1 ...
- 关于JavaScript设计模式的学习(二)
第二部分来了,是关于结构型的,同样的,还是在简书中,GitHub上也有代码示例和详细注释 简书:http://www.jianshu.com/p/face1be4b846 github:https:/ ...
- Javascript经典算法学习1:产生随机数组的辅助类
辅助类 在几个经典排序算法学习部分,为方便统一测试不同算法,新建了一个辅助类,主要功能为:产生指定长度的随机数组,提供打印输出数组,交换两个元素等功能,代码如下: function ArraySort ...
- JavaScript学习总结(二)——闭包、IIFE、apply、函数与对象
一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...
- javascript oop深入学习笔记(二)--javascript的函数
一.概述: 函数是进行模块化程序设计的基础, javascript重的的函数不同于其他语言,每个函数都作为一个对象被维护和运行.通过函数对象的性质,可以很方便的将一个函数赋值给一个变量或则讲函数作为参 ...
随机推荐
- 全屏使用swiper.js过程中遇到的坑
概述 swiper.js确实是一个很好用的插件,下面记录下我在全屏使用过程中遇到的一些坑和解决办法,供以后开发时参考,相信对其他人也有用. 通用方案 一般来说,swiper需要放在body的下一层,虽 ...
- 如何做好错误处理?(PHP篇)
起因 之前我在封装 PHP 一个类库的时候,如果有遇到错误(例如构造函数传参不合法的话),则直接 die() ,后来发现这种方法很不好,会直接退出程序. 所以我想到给 PHP 上异常捕获的机制了. 错 ...
- 文件分享系统(Django)
- DockerFile(保你会版本)(七)
一.什么是dockerfile Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile自定义快速创建属于自己的镜像,Dockerfile是通过很多的参数指令编写的文件,通过do ...
- macbook 安装oracle RAC
http://blog.itpub.net/29047826/viewspace-1268923/ http://blog.itpub.net/24930246/viewspace-1426856/
- Kafka连接SparkStreaming的两种方式
第一种方式代码: import org.apache.spark.storage.StorageLevel import org.apache.spark.{HashPartitioner, Spar ...
- TensorFlow.js之根据数据拟合曲线
这篇文章中,我们将使用TensorFlow.js来根据数据拟合曲线.即使用多项式产生数据然后再改变其中某些数据(点),然后我们会训练模型来找到用于产生这些数据的多项式的系数.简单的说,就是给一些在二维 ...
- Spring Boot 基础概述与相关约定配置
今天打算整理一下 Spring Boot 的基础篇,这系列的文章是我业余时间来写的,起源于之前对微服务比较感兴趣,微服务的范畴比较广包括服务治理.负载均衡.断路器.配置中心.API网关等,还需要结合 ...
- Jenkins使用TFS部署
之前发表过一篇Jenkins的文章 使用Jenkins部署.Net应用程序 里面是使用GIT做的版本管理 今天更新下使用TFS做版本管理 首先在插件管理中搜索tfs,我这里因为已经装了,所以在已安装列 ...
- 使用java调用fastDFS客户端进行静态资源文件上传
一.背景 上篇博客我介绍了FastDFS的概念.原理以及安装步骤,这篇文章我们来聊一聊如何在java中使用FastDFSClient进行静态资源的上传. 二.使用步骤 1.开发环境 spring+sp ...