📄 randomlib.c
字号:
alv = log(v); if(alv < ynorm-amaxp) goto S170; if(alv > ynorm+amaxp) goto S30;/* STIRLING'S FORMULA TO MACHINE ACCURACY FOR THE FINAL ACCEPTANCE/REJECTION TEST*/ x1 = ix+1.0; f1 = fm+1.0; z = n+1.0-fm; w = n-ix+1.0; z2 = z*z; x2 = x1*x1; f2 = f1*f1; w2 = w*w; if(alv <= xm*log(f1/x1)+(n-m+0.5)*log(z/w)+(ix-m)*log(w*p/(x1*q))+(13860.0- (462.0-(132.0-(99.0-140.0/f2)/f2)/f2)/f2)/f1/166320.0+(13860.0-(462.0- (132.0-(99.0-140.0/z2)/z2)/z2)/z2)/z/166320.0+(13860.0-(462.0-(132.0- (99.0-140.0/x2)/x2)/x2)/x2)/x1/166320.0+(13860.0-(462.0-(132.0-(99.0 -140.0/w2)/w2)/w2)/w2)/w/166320.0) goto S170; goto S30;S140:/* INVERSE CDF LOGIC FOR MEAN LESS THAN 30*/ qn = pow(q,(double)n); r = p/q; g = r*(n+1);S150: ix = 0; f = qn; u = ranf();S160: if(u < f) goto S170; if(ix > 110) goto S150; u -= f; ix += 1; f *= (g/ix-r); goto S160;S170: if(psave > 0.5) ix = n-ix; ignbin = ix; return ignbin;}long ignnbn(long n,float p)/*********************************************************************** long ignnbn(long n,float p) GENerate Negative BiNomial random deviate Function Generates a single random deviate from a negative binomial distribution. Arguments N --> The number of trials in the negative binomial distribution from which a random deviate is to be generated. JJV (N > 0) P --> The probability of an event. JJV (0.0 < P < 1.0) Method Algorithm from page 480 of Devroye, Luc Non-Uniform Random Variate Generation. Springer-Verlag, New York, 1986.***********************************************************************/{static long ignnbn;static float y,a,r;/* .. .. Executable Statements ..*//* Check Arguments*/ if(n <= 0L) ftnstop("N <= 0 in IGNNBN"); if(p <= 0.0F) ftnstop("P <= 0.0 in IGNNBN"); if(p >= 1.0F) ftnstop("P >= 1.0 in IGNNBN");/* Generate Y, a random gamma (n,(1-p)/p) variable JJV Note: the above parametrization is consistent with Devroye, JJV but gamma (p/(1-p),n) is the equivalent in our code*/ r = (float)n; a = p/(1.0F-p);/* * JJV changed this to call SGAMMA directly * y = gengam(a,r); <- OLD */ y = sgamma(r)/a;/* Generate a random Poisson(y) variable*/ ignnbn = ignpoi(y); return ignnbn;}long ignpoi(float mu)/*********************************************************************** long ignpoi(float mu) GENerate POIsson random deviate Function Generates a single random deviate from a Poisson distribution with mean MU. Arguments mu --> The mean of the Poisson distribution from which a random deviate is to be generated. (mu >= 0.0) ignpoi <-- The random deviate. Method Renames KPOIS from TOMS as slightly modified by BWB to use RANF instead of SUNIF. For details see: Ahrens, J.H. and Dieter, U. Computer Generation of Poisson Deviates From Modified Normal Distributions. ACM Trans. Math. Software, 8, 2 (June 1982),163-179******************************************************************************************************************************************** P O I S S O N DISTRIBUTION ******************************************************************************************************************************************** FOR DETAILS SEE: AHRENS, J.H. AND DIETER, U. COMPUTER GENERATION OF POISSON DEVIATES FROM MODIFIED NORMAL DISTRIBUTIONS. ACM TRANS. MATH. SOFTWARE, 8,2 (JUNE 1982), 163 - 179. (SLIGHTLY MODIFIED VERSION OF THE PROGRAM IN THE ABOVE ARTICLE) ********************************************************************** INTEGER FUNCTION IGNPOI(IR,MU) INPUT: IR=CURRENT STATE OF BASIC RANDOM NUMBER GENERATOR MU=MEAN MU OF THE POISSON DISTRIBUTION OUTPUT: IGNPOI=SAMPLE FROM THE POISSON-(MU)-DISTRIBUTION MUPREV=PREVIOUS MU, MUOLD=MU AT LAST EXECUTION OF STEP P OR B. TABLES: COEFFICIENTS A0-A7 FOR STEP F. FACTORIALS FACT COEFFICIENTS A(K) - FOR PX = FK*V*V*SUM(A(K)*V**K)-DEL SEPARATION OF CASES A AND B*/{extern float fsign( float num, float sign );static float a0 = -0.5;static float a1 = 0.3333333;static float a2 = -0.2500068;static float a3 = 0.2000118;static float a4 = -0.1661269;static float a5 = 0.1421878;static float a6 = -0.1384794;static float a7 = 0.125006;/* JJV changed the initial values of MUPREV and MUOLD */static float muold = -1.0E37;static float muprev = -1.0E37;static float fact[10] = { 1.0,1.0,2.0,6.0,24.0,120.0,720.0,5040.0,40320.0,362880.0};/* JJV added ll to the list, for Case A */static long ignpoi,j,k,kflag,l,ll,m;static float b1,b2,c,c0,c1,c2,c3,d,del,difmuk,e,fk,fx,fy,g,omega,p,p0,px,py,q,s, t,u,v,x,xx,pp[35]; if(mu == muprev) goto S10; if(mu < 10.0) goto S120;/* C A S E A. (RECALCULATION OF S,D,LL IF MU HAS CHANGED) JJV changed l in Case A to ll*/ muprev = mu; s = sqrt(mu); d = 6.0*mu*mu;/* THE POISSON PROBABILITIES PK EXCEED THE DISCRETE NORMAL PROBABILITIES FK WHENEVER K >= M(MU). LL=IFIX(MU-1.1484) IS AN UPPER BOUND TO M(MU) FOR ALL MU >= 10 .*/ ll = (long) (mu-1.1484);S10:/* STEP N. NORMAL SAMPLE - SNORM(IR) FOR STANDARD NORMAL DEVIATE*/ g = mu+s*snorm(); if(g < 0.0) goto S20; ignpoi = (long) (g);/* STEP I. IMMEDIATE ACCEPTANCE IF IGNPOI IS LARGE ENOUGH*/ if(ignpoi >= ll) return ignpoi;/* STEP S. SQUEEZE ACCEPTANCE - SUNIF(IR) FOR (0,1)-SAMPLE U*/ fk = (float)ignpoi; difmuk = mu-fk; u = ranf(); if(d*u >= difmuk*difmuk*difmuk) return ignpoi;S20:/* STEP P. PREPARATIONS FOR STEPS Q AND H. (RECALCULATIONS OF PARAMETERS IF NECESSARY) .3989423=(2*PI)**(-.5) .416667E-1=1./24. .1428571=1./7. THE QUANTITIES B1, B2, C3, C2, C1, C0 ARE FOR THE HERMITE APPROXIMATIONS TO THE DISCRETE NORMAL PROBABILITIES FK. C=.1069/MU GUARANTEES MAJORIZATION BY THE 'HAT'-FUNCTION.*/ if(mu == muold) goto S30; muold = mu; omega = 0.3989423/s; b1 = 4.166667E-2/mu; b2 = 0.3*b1*b1; c3 = 0.1428571*b1*b2; c2 = b2-15.0*c3; c1 = b1-6.0*b2+45.0*c3; c0 = 1.0-b1+3.0*b2-15.0*c3; c = 0.1069/mu;S30: if(g < 0.0) goto S50;/* 'SUBROUTINE' F IS CALLED (KFLAG=0 FOR CORRECT RETURN)*/ kflag = 0; goto S70;S40:/* STEP Q. QUOTIENT ACCEPTANCE (RARE CASE)*/ if(fy-u*fy <= py*exp(px-fx)) return ignpoi;S50:/* STEP E. EXPONENTIAL SAMPLE - SEXPO(IR) FOR STANDARD EXPONENTIAL DEVIATE E AND SAMPLE T FROM THE LAPLACE 'HAT' (IF T <= -.6744 THEN PK < FK FOR ALL MU >= 10.)*/ e = sexpo(); u = ranf(); u += (u-1.0); t = 1.8+fsign(e,u); if(t <= -0.6744) goto S50; ignpoi = (long) (mu+s*t); fk = (float)ignpoi; difmuk = mu-fk;/* 'SUBROUTINE' F IS CALLED (KFLAG=1 FOR CORRECT RETURN)*/ kflag = 1; goto S70;S60:/* STEP H. HAT ACCEPTANCE (E IS REPEATED ON REJECTION)*/ if(c*fabs(u) > py*exp(px+e)-fy*exp(fx+e)) goto S50; return ignpoi;S70:/* STEP F. 'SUBROUTINE' F. CALCULATION OF PX,PY,FX,FY. CASE IGNPOI .LT. 10 USES FACTORIALS FROM TABLE FACT*/ if(ignpoi >= 10) goto S80; px = -mu; py = pow(mu,(double)ignpoi)/ *(fact+ignpoi); goto S110;S80:/* CASE IGNPOI .GE. 10 USES POLYNOMIAL APPROXIMATION A0-A7 FOR ACCURACY WHEN ADVISABLE .8333333E-1=1./12. .3989423=(2*PI)**(-.5)*/ del = 8.333333E-2/fk; del -= (4.8*del*del*del); v = difmuk/fk; if(fabs(v) <= 0.25) goto S90; px = fk*log(1.0+v)-difmuk-del; goto S100;S90: px = fk*v*v*(((((((a7*v+a6)*v+a5)*v+a4)*v+a3)*v+a2)*v+a1)*v+a0)-del;S100: py = 0.3989423/sqrt(fk);S110: x = (0.5-difmuk)/s; xx = x*x; fx = -0.5*xx; fy = omega*(((c3*xx+c2)*xx+c1)*xx+c0); if(kflag <= 0) goto S40; goto S60;S120:/* C A S E B. (START NEW TABLE AND CALCULATE P0 IF NECESSARY) JJV changed MUPREV assignment to initial value*/ muprev = -1.0E37; if(mu == muold) goto S130;/* JJV added argument checker here */ if(mu >= 0.0) goto S125; mexPrintf("MU < 0 in IGNPOI: MU %16.6E\n",mu); mexErrMsgTxt("Problem generating poisson deviate"); exit(1);S125: muold = mu; m = max(1L,(long) (mu)); l = 0; p = exp(-mu); q = p0 = p;S130:/* STEP U. UNIFORM SAMPLE FOR INVERSION METHOD*/ u = ranf(); ignpoi = 0; if(u <= p0) return ignpoi;/* STEP T. TABLE COMPARISON UNTIL THE END PP(L) OF THE PP-TABLE OF CUMULATIVE POISSON PROBABILITIES (0.458=PP(9) FOR MU=10)*/ if(l == 0) goto S150; j = 1; if(u > 0.458) j = min(l,m); for(k=j; k<=l; k++) { if(u <= *(pp+k-1)) goto S180; } if(l == 35) goto S130;S150:/* STEP C. CREATION OF NEW POISSON PROBABILITIES P AND THEIR CUMULATIVES Q=PP(K)*/ l += 1; for(k=l; k<=35; k++) { p = p*mu/(float)k; q += p; *(pp+k-1) = q; if(u <= q) goto S170; } l = 35; goto S130;S170: l = k;S180: ignpoi = k; return ignpoi;}long ignuin(long low,long high)/*********************************************************************** long ignuin(long low,long high) GeNerate Uniform INteger Function Generates an integer uniformly distributed between LOW and HIGH. Arguments low --> Low bound (inclusive) on integer value to be generated high --> High bound (inclusive) on integer value to be generated Note If (HIGH-LOW) > 2,147,483,561 prints error message on * unit and stops the program.********************************************************************** IGNLGI generates integers between 1 and 2147483562 MAXNUM is 1 less than maximum generable value*/{#define maxnum 2147483561Lstatic long ignuin,ign,maxnow,range,ranp1; if(!(low > high)) goto S10; exit(1);S10: range = high-low; if(!(range > maxnum)) goto S20; exit(1);S20: if(!(low == high)) goto S30; ignuin = low; return ignuin;S30:/* Number to be generated should be in range 0..RANGE Set MAXNOW so that the number of integers in 0..MAXNOW is an integral multiple of the number in 0..RANGE*/ ranp1 = range+1; maxnow = maxnum/ranp1*ranp1;S40: ign = ignlgi()-1; if(!(ign <= maxnow)) goto S40; ignuin = low+ign%ranp1; return ignuin;#undef maxnum#undef err1#undef err2}long lennob( char *str )/* Returns the length of str ignoring trailing blanks but not other white space.*/{long i, i_nb;for (i=0, i_nb= -1L; *(str+i); i++) if ( *(str+i) != ' ' ) i_nb = i;return (i_nb+1); }long mltmod(long a,long s,long m)/*********************************************************************** long mltmod(long a,long s,long m) Returns (A*S) MOD M This is a transcription from Pascal to Fortran of routine MULtMod_Decompos from the paper L'Ecuyer, P. and Cote, S. "Implementing a Random Number Package with Splitting Facilities." ACM Transactions on Mathematical Software, 17:98-111 (1991) Arguments a, s, m -->***********************************************************************/{#define h 32768Lstatic long mltmod,a0,a1,k,p,q,qh,rh;/* H = 2**((b-2)/2) where b = 32 because we are using a 32 bit machine. On a different machine recompute H*/ if(!(a <= 0 || a >= m || s <= 0 || s >= m)) goto S10; mexPrintf(" a = %12ld s = %12ld m = %12ld\n",a,s,m); mexErrMsgTxt("Problem generating multinomial deviate"); exit(1);S10: if(!(a < h)) goto S20; a0 = a; p = 0; goto S120;S20: a1 = a/h; a0 = a-h*a1; qh = m/h; rh = m-h*qh; if(!(a1 >= h)) goto S50; a1 -= h; k = s/qh; p = h*(s-k*qh)-k*rh;S30: if(!(p < 0)) goto S40; p += m; goto S30;S40: goto S60;S50:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -