📄 dist.cpp
字号:
// UniformDist.cpp: implementation of the UniformDist class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Dist.h"
#include <limits.h>
#include <math.h>
#include <stdio.h>
//------------------------------- RandSeed -------------------------------
UniformDist *RandSeed::ran1 = new UniformDist(INIT_SEED);
void RandSeed::set_seed(long new_seed)
{
delete ran1;
ran1 = new UniformDist(new_seed);
}
long RandSeed::new_seed(void)
{
float ans;
ans = (*ran1)();
ans *= (*ran1)();
// cout << "rand_seed : " << idum << " " << long(-MAXLONG * ans) << endl;
return long(-LONG_MAX * ans);
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
#define NTAB 32
#define NDIV (1+(IM-1)/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)
// "Minimal" random number generator of Park and Miller with
// Bays-Durham shuffle and added safeguards. Returns a uniform random
// deviate between 0.0 and 1.0 (exclusive of the endpoint values).
// Call with idum a negative integer to initialize; thereafter, do not
// alter idum between successive deviates in a sequence. RNMX should
// approximate the largest flating value that is less than 1.
float UniformDist::ran1(void)
{
int j;
long k;
float temp;
if (idum <= 0 || !iy) { // Initialize
if (-idum < 1) // Be sure to prevent idum = 0
idum = 1;
else
idum = -idum;
for (j = NTAB+7; j >= 0; j-- ) // Load the shuffle table (after 8 warmups)
{
k = idum/IQ;
idum = IA * (idum-k*IQ) - IR*k;
if (idum < 0) idum += IM;
if (j < NTAB) iv[j] = idum;
}
iy = iv[0];
}
k = idum/IQ; // Start here when not initializing.
idum = IA * (idum-k*IQ) - IR*k; // Compute idum = (IA*idum) % IM without
if (idum < 0) idum += IM; // overflows by Schrage's method.
j = iy/NDIV; // Will be in the range 0..NTAB-1
iy = iv[j]; // Output previously stored value and
iv[j] = idum; // and refull the shuffle table.
if ((temp = AM*iy) > RNMX) // Because users don't expect endpoint values
return RNMX;
else
return temp;
}
float NormalDist::gasdev(void)
// returns a normally distributed deviate with zero mean and unit
// variance, using ran1(idum) as the source of uniform deviates.
{
float fac,rsq,v1,v2;
if (iset == 0) { // We don't have an extra deviate handy, so
do {
v1=2.0*(*ran1)()-1.0; // pick two uniform numbers in the square
v2=2.0*(*ran1)()-1.0; // extending from -1 to +1 in each direction,
rsq=v1*v1+v2*v2; // see if they are in the unit circle
} while (rsq >= 1.0 || rsq == 0.0); // and if they are not, try again.
fac=sqrt(-2.0*log(rsq)/rsq);
// Now make the box-Muller transformation to get two normal
// devites. Return one and save the other for next time.
gset=v1*fac;
iset=1; // Set flag.
return v2*fac;
}
else { // We have an extra deviate handy,
iset=0; // so unset the flag,
return gset; // and return it.
}
}
float ExpDist::expdev(void)
// Returns an exponentially distributed, positive, random deviate of
// unit mean, using ran1(idum) as the source of uniform deviates.
{
float dum;
do
dum = (*ran1)();
while (dum == 0.0);
return -log(dum);
}
#define PI 3.141592654
float PoissonDist::poidev(float xm)
// Returns as a floating-point number an integer value that is a
// random deviate drawn from a Poisson distribution of mean xm, using
// ran1(idum) as a source of uniform random deviates.
{
float gammln(float xx);
float em,t,y;
if (xm < 12.0) {
if (xm != oldm) {
oldm=xm;
g=exp(-xm);
}
em = -1;
t=1.0;
do {
em += 1.0;
t *= (*ran1)();
} while (t > g);
}
else {
if (xm != oldm) {
oldm=xm;
sq=sqrt(2.0*xm);
alxm=log(xm);
g=xm*alxm-gammln(xm+1.0);
}
do {
do {
y=tan(PI*(*ran1)());
em=sq*y+xm;
} while (em < 0.0);
em=floor(em);
t=0.9*(1.0+y*y)*exp(em*alxm-gammln(em+1.0)-g);
} while ((*ran1)() > t);
}
return em;
}
#undef PI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -