⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pseudorandom.cpp

📁 随机数类,产生随机数
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		else
        {
			return 1 ;
        }
    }
}

/**** The Multivariate Gaussian Distribution ****/
/*Random vectors from a multivariate Normal distribution
 *CALL:  r = mnormrnd(n,mu,S)
 * r = matrix of random numbers from the multivariate normal
 *     distribution with mean mu and covariance matrix S.
 * n = number of sample vectors
 * method = 'svd'  Singular value decomp.  (stable, quite fast)
 * S must be a symmetric, semi-positive definite matrix with size equal
 * to the length of mu.
 * Example
 * mu = [0 5]; S = [1 0.45; 0.45 0.25];
 * r = mnormrnd(100,mu,S)
 */
Matrix<double> PseudoRandom::mnormrnd(int cases, Matrix<double> & mu, Matrix<double> & sigma)
{
	int m;
	m = sigma.RowNum();
	
    Matrix<double> w(m,1),v(m,m),U(m,m),T(m,m),r(m,cases),randn(m,cases),mu_matrix(m,cases);
	// Cholesky decomposition
	U = sigma.Chold();
    T = U.Tran();
	
	for (int i=1;i<=m;i++){
		for (int j=1;j<=cases;j++){
			randn.SetValue(i,j,gaussian(0.0,1.0));
			mu_matrix.SetValue(i,j,mu(i,1));
		}
	}
	//cout <<mu_matrix<<endl;
	//cout <<prod(T,randn)<<endl;
	r = T*randn + mu_matrix;
	//cout<<r<<endl;
	return r;
}
/**** The Truncated Multivariate Gaussian Distribution ****/
/*Procedure for drawing from truncated multivariate normal based on
Geweke's code. i.e draws from
     xdraw is N(amu,sigma) subject to a < d*x < b
     where N(.,) in the n-variate Normal, a and b are nx1
Note that d is restricted to being a nonsingular nxn matrix
la and lb are nx1 vectors set to one if no upper/lower bounds
kstep=order of Gibbs within the constraint rows
*/
Matrix<double> PseudoRandom::tnorm_rnd(int n, Matrix<double> & amu, Matrix<double> & sigma, Matrix<double> & a, 
	                         Matrix<double> & b,Matrix<double> & la, Matrix<double> & lb, Matrix<double> & d,Matrix<int> & kstep)
{	
	int niter=10;
	double t1,aa;
	int m = amu.RowNum();
	//transform to work in terms of z=d*x
	Matrix<double> z(m,1), anu(m,1), a1(m,1), b1(m,1), h(m,1), xdraw(m,1);
	Matrix<int> indx(n,1);
	Matrix<double> d_copy(m,m), dinv(m,m), tau(m,m), tau_(m,m), tau_copy(m,m), tauinv(m,m), c(m,m), xdraw_matrix(m,n);
	for (int col=1;col<=n;col++){
		
		d_copy = d;
		dinv = d_copy.Inv();
		anu = d * amu;
		
		tau_ = d*sigma;
		tau = tau_*(d.Tran());
	
		tau_copy = tau;
		tauinv = tau_copy.Inv();
	
		a1 = a - anu;
		b1 = b - anu;
		for (int i=1; i<=m; i++)
		{
			aa = tauinv(i,i);
			h.SetValue(i,1,1/sqrt(aa));
			for (int j=1; j<=m; j++)
			{
				c.SetValue(i,j,-tauinv(i,j)/aa);
			}
		}
		
		for (int initer=1; initer<=niter; initer++)
		{
			for (int k=1; k<=m; k++)
			{
				int i = kstep(k,1);
				aa = 0;
				for (int j=1; j<=m; j++)
				{
					if (i != j)
					{
						aa = aa + c(i,j) * z(j,1);
					}
				}
				
				if (la(i,1)==1)
				{
					t1=normrt_rnd(0,1,(b1(i,1)-aa)/h(i,1));
				}
				else 
				if (lb(i,1)==1)
				{
					t1=normlt_rnd(0,1,(a1(i,1)-aa)/h(i,1));
				}
				else
				{
					t1=normt_rnd(0,1,(a1(i,1)-aa)/h(i,1),(b1(i,1)-aa)/h(i,1));
				}
				z.SetValue(i,1,aa + h(i,1)*t1);
				}
		}
		
		//Transform back to x
		xdraw = dinv*z;
		for (int row=1; row<=m; row++)
		{
			xdraw_matrix.SetValue(row,col,xdraw(row,1) + amu(row,1));
		}
	}
		return xdraw_matrix;
}


/**** The Gaussian Distribution PDF****/
double PseudoRandom::gaussian_pdf(const double x, const double mu, const double sigma)
{
	double u;
	double p;
	
	u = (x - mu) / fabs(sigma);
	p = (1 / (sqrt (2 * M_PI) * fabs (sigma))) * exp (-u * u / 2);
	
	return p;
}

/**** The Bivariate Gaussian Distribution PDF****/
double PseudoRandom::bivariate_gaussian_pdf(const double x, const double y, const double sigma_x, const double sigma_y, const double rho)
{
  double u = x / sigma_x ;
  double v = y / sigma_y ;
  double c = 1 - rho*rho ;
  double p = (1 / (2 * M_PI * sigma_x * sigma_y * sqrt(c))) 
    * exp (-(u * u - 2 * rho * u * v + v * v) / (2 * c));
  return p;
}

/**** The Exponential Distribution PDF****/
double PseudoRandom::exponential_pdf(const double x, const double mu)
{
  if (x < 0)
    {
      return 0 ;
    }
  else
    {
      double p = exp (-x/mu)/mu;
      
      return p;
    }
}

/**** The Uniform Distribution PDF****/
double PseudoRandom::flat_pdf(double x, const double a, const double b)
{
  if (x < b && x >= a)
    {
      return 1 / (b - a);
    }
  else
    {
      return 0;
    }
}

//export template <class T>
//T PseudoRandom::mean(const T data[], const unsigned int stride, const unsigned int size)
//{
//	/* Compute the arithmetic mean of a dataset using the recurrence relation 
//     mean_(n) = mean(n-1) + (data[n] - mean(n-1))/(n+1)   */
//
//	long double mean = 0;
//	unsigned int i;
//
//	for (i = 0; i < size; i++)
//    {
//		mean += (data[i * stride] - mean) / (i + 1);
//    }
//
//  return mean;
//}
	

/*** Others  ***/

double PseudoRandom::gamma_int(const unsigned int a)
{
	if (a < 12)
	{
		unsigned int i;
      	double prod = 1;
      	
      	for (i = 0; i < a; i++)
        {
        	prod *= randDblExc();
        }
        
        /* Note: for 12 iterations we are safe against underflow, since
         * the smallest positive random number is O(2^-32). This means
         * the smallest possible product is 2^(-12*32) = 10^-116 which
         * is within the range of double precision. 
         */
         
         return -log (prod);
	}
	else
	{
		return gamma_large((double) a);
	}
}

double PseudoRandom::gamma_large(const double a)
{
	/* Works only if a > 1, and is most efficient if a is large
	 * This algorithm, reported in Knuth, is attributed to Ahrens.  A
	 * faster one, we are told, can be found in: J. H. Ahrens and
	 * U. Dieter, Computing 12 (1974) 223-246.  
	 */
     
	double sqa, x, y, v;
	sqa = sqrt (2 * a - 1);
  	do
  	{
  		do
  		{
			y = tan (M_PI * randExc());
			x = sqa * y + a - 1;
  		}
  		while (x <= 0);
  		v = randExc();
  	}
  	while (v > (1 + y * y) * exp ((a - 1) * log (x / (a - 1)) - sqa * y));
  		
  	return x;
}

double PseudoRandom::gamma_frac(const double a)
{
	// This is exercise 16 from Knuth; see page 135, and the solution is on page 551.
     
	double p, q, x, u, v;
	p = M_E / (a + M_E);
	do
	{
		u = randExc();
		v = randDblExc();
		
		if (u < p)
		{
			x = exp ((1 / a) * log (v));
			q = exp (-x);
		}
		else
		{
			 x = 1 - log (v);
			 q = exp ((a - 1) * log (x));
		}
	}
	while (randExc() >= q);
	
	return x;
}

double PseudoRandom::normal_01_cdf ( double x )
{
  double a1 = 0.398942280444E+00;
  double a2 = 0.399903438504E+00;
  double a3 = 5.75885480458E+00;
  double a4 = 29.8213557808E+00;
  double a5 = 2.62433121679E+00;
  double a6 = 48.6959930692E+00;
  double a7 = 5.92885724438E+00;
  double b0 = 0.398942280385E+00;
  double b1 = 3.8052E-08;
  double b2 = 1.00000615302E+00;
  double b3 = 3.98064794E-04;
  double b4 = 1.98615381364E+00;
  double b5 = 0.151679116635E+00;
  double b6 = 5.29330324926E+00;
  double b7 = 4.8385912808E+00;
  double b8 = 15.1508972451E+00;
  double b9 = 0.742380924027E+00;
  double b10 = 30.789933034E+00;
  double b11 = 3.99019417011E+00;
  double cdf;
  double q;
  double y;
//
//  |X| <= 1.28.
//
  if ( fabs ( x ) <= 1.28 )
  {
    y = 0.5 * x * x;

    q = 0.5 - fabs ( x ) * ( a1 - a2 * y / ( y + a3 - a4 / ( y + a5 
      + a6 / ( y + a7 ) ) ) );
//
//  1.28 < |X| <= 12.7
//
  }
  else if ( fabs ( x ) <= 12.7 )
  {
    y = 0.5 * x * x;

    q = exp ( - y ) * b0 / ( fabs ( x ) - b1 
      + b2 / ( fabs ( x ) + b3 
      + b4 / ( fabs ( x ) - b5 
      + b6 / ( fabs ( x ) + b7 
      - b8 / ( fabs ( x ) + b9 
      + b10 / ( fabs ( x ) + b11 ) ) ) ) ) );
//
//  12.7 < |X|
//
  }
  else
  {
    q = 0.0;
  }
//
//  Take account of negative X.
//
  if ( x < 0.0 )
  {
    cdf = q;
  }
  else
  {
    cdf = 1.0 - q;
  }

  return cdf;
}

double PseudoRandom::normal_01_cdf_inv ( double p )
{
  double a[8] = { 
    3.3871328727963666080,     1.3314166789178437745e+2,
    1.9715909503065514427e+3,  1.3731693765509461125e+4,
    4.5921953931549871457e+4,  6.7265770927008700853e+4,
    3.3430575583588128105e+4,  2.5090809287301226727e+3 };
  double b[8] = {
    1.0,                       4.2313330701600911252e+1,
    6.8718700749205790830e+2,  5.3941960214247511077e+3,
    2.1213794301586595867e+4,  3.9307895800092710610e+4,
    2.8729085735721942674e+4,  5.2264952788528545610e+3 };
  double c[8] = {
    1.42343711074968357734,     4.63033784615654529590,
    5.76949722146069140550,     3.64784832476320460504,
    1.27045825245236838258,     2.41780725177450611770e-1,
    2.27238449892691845833e-2,  7.74545014278341407640e-4 };
  double const1 = 0.180625;
  double const2 = 1.6;
  double d[8] = {
    1.0,                        2.05319162663775882187,
    1.67638483018380384940,     6.89767334985100004550e-1,
    1.48103976427480074590e-1,  1.51986665636164571966e-2,
    5.47593808499534494600e-4,  1.05075007164441684324e-9 };
  double e[8] = {
    6.65790464350110377720,     5.46378491116411436990,
    1.78482653991729133580,     2.96560571828504891230e-1,
    2.65321895265761230930e-2,  1.24266094738807843860e-3,
    2.71155556874348757815e-5,  2.01033439929228813265e-7 };
  double f[8] = {
    1.0,                        5.99832206555887937690e-1,
    1.36929880922735805310e-1,  1.48753612908506148525e-2,
    7.86869131145613259100e-4,  1.84631831751005468180e-5,
    1.42151175831644588870e-7,  2.04426310338993978564e-15 };
  double q;
  double r;
  double split1 = 0.425;
  double split2 = 5.0;
  double value;

  if ( p <= 0.0 )
  {
    value = -d_huge ( );
    return value;
  }

  if ( 1.0 <= p )
  {
    value = d_huge ( );
    return value;
  }

  q = p - 0.5;

  if ( fabs ( q ) <= split1 )
  {
    r = const1 - q * q;
    value = q * dpoly_value ( 8, a, r ) / dpoly_value ( 8, b, r );
  }
  else
  {
    if ( q < 0.0 )
    {
      r = p;
    }
    else
    {
      r = 1.0 - p;
    }

    if ( r <= 0.0 )
    {
      value = -1.0;
      exit ( 1 );
    }

    r = sqrt ( -log ( r ) );

    if ( r <= split2 )
    {
      r = r - const2;
      value = dpoly_value ( 8, c, r ) / dpoly_value ( 8, d, r ); 
     }
     else
     {
       r = r - split2;
       value = dpoly_value ( 8, e, r ) / dpoly_value ( 8, f, r );
    }

    if ( q < 0.0 )
    {
      value = -value;
    }

  }

  return value;
}

double PseudoRandom::d_huge ( void )
{
  return HUGE_VAL;
}

double PseudoRandom::dpoly_value ( int n, double a[], double x )
{
	{
  int i;
  double value;

  value = 0.0;

  for ( i = n-1; 0 <= i; i-- )
  {
    value = value * x + a[i];
  }

  return value;
}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -