天天看點

正态分布随機數生成法(java版)

 要程式設計得到服從均勻分布的僞随機數是容易的。C語言、Java語言等都提供了相應的函數。但是要想生成服從正态分布的随機數就沒那麼容易了。 

       得到服從正态分布的随機數的基本思想是先得到服從均勻分布的随機數,再将服從均勻分布的随機數轉變為服從正态分布。接下來就先分析三個從均勻分布到正态分布轉變的方法。然後程式設計實作其中的兩個方法并對程式實作運作的效果進行統計分析。

1、 方法分析 

(1) 利用分布函數的反函數 

若要得到分布函數為F(x)的随機變量Y。 

可令

正态分布随機數生成法(java版)

, 其中u是服從均勻分布的随機變量,有 

正态分布随機數生成法(java版)

因而,對于任意的分布函數,隻要求出它的反函數,就可以由服從均勻分布的随機變量執行個體來生成服從該分布函數的随機變量執行個體。 

現在來看正态分布的分布函數,對于

正态分布随機數生成法(java版)

,其分布函數為: 

正态分布随機數生成法(java版)

顯然,要想求其反函數是相當困難的,同時要想程式設計實作也很複雜。可見,用此種方法來生成服從正态分布的随機變量執行個體并不可取。

(2) 利用中心極限定理 

第二種方法利用林德伯格—萊維(Lindeberg—Levi)中心極限定理:如果随機變量序列

正态分布随機數生成法(java版)

獨立同分布,并且具有有限的數學期望和方差

正态分布随機數生成法(java版)

則對一切x∈R有

正态分布随機數生成法(java版)

是以,對于服從均勻分布的随機變量Xi,隻要n充分大,随機變量

正态分布随機數生成法(java版)

為正态分布。我們将實作這一方法。這裡 Ri為[0,1]之間均勻分布的随機數

package cn.tan.basicmath;
	/**
	 * 
	 * @author Özil ισνΞ
	 *
	 */
public class RanZT {
	
	/**
	 * 這裡是我上一篇日記裡面産生[0,1]随機數的算法
	 * @param r 将變量的位址傳進函數中,以便每次調用後更新随機種子的值,否則将得到完全一樣的資料進而失去随機性
	 * 這裡r我們初始化為5
	 * @return
	 */
	static double seftRandom(double[] r){
		double base,u,v,p,temp1,temp2,temp3;
		//基數
		base = 256.0;
		//兩個常數 uv;
		u = 17.0;
		v = 139.0;
		//計算總值
		temp1 = u*(r[0])+v;
		//計算商
		temp2 = (int)(temp1/base);
		//計算餘數,1到base的餘數
		temp3 = temp1 - temp2*base;
		//更新随機種子,為下一次使用
		r[0] = temp3;
		//随機數指派 ,擷取[0,1]的随機數
		p = r[0]/base;
		return p;
	}
	
	/**
	 * 正态分布随機數生成法
	 * @param u	正态分布的均值
	 * @param t	正态分布的方差0
	 * @param r	随機種子
	 * @param n	正态分布公式的n
	 * @return
	 */
	static double randZT(double u,double t,double[]r,double n){
		int i;
		double total = 0.0;
		double result;
		for(i = 0;i<n;i++){
			//累加
			total += seftRandom(r);
		}
		//得到的随機數
		result = u+t*((total-n/2.0)/Math.sqrt(n/12));
		return result;
	}
	
	public static void main(String[] args){
		int i;
		double u,t,n;
		double[] r = {5.0};
		//初始化正态分布的均值和方差
		u = 2.0;
		t = 3.5;
		n = 12.0;
		System.out.println("産生十個正态分布的随機數:");
		//循環調用
		for(i = 0;i<10;i++){
			System.out.printf("%10.5f\n",randZT(u,t,r,n));
		}
		System.out.println();
	}
}
           
正态分布随機數生成法(java版)