📄 ranlib.c
字号:
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;static float muold = 0.0;static float muprev = 0.0;static float fact[10] = { 1.0,1.0,2.0,6.0,24.0,120.0,720.0,5040.0,40320.0,362880.0};static long ignpoi,j,k,kflag,l,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,L IF MU HAS CHANGED)*/ muprev = mu; s = sqrt(mu); d = 6.0*mu*mu;/* THE POISSON PROBABILITIES PK EXCEED THE DISCRETE NORMAL PROBABILITIES FK WHENEVER K >= M(MU). L=IFIX(MU-1.1484) IS AN UPPER BOUND TO M(MU) FOR ALL MU >= 10 .*/ l = (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 >= l) 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)*/ muprev = 0.0; if(mu == muold) goto S130; 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; fputs(" low > high in ignuin - ABORT",stderr); exit(1);S10: range = high-low; if(!(range > maxnum)) goto S20; fputs(" high - low too large in ignuin - ABORT",stderr); 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 S50; ignuin = low+ign%ranp1; return ignuin;S50: goto S40;#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; fputs(" a, m, s out of order in mltmod - ABORT!",stderr); fprintf(stderr," a = %12ld s = %12ld m = %12ld\n",a,s,m); fputs(" mltmod requires: 0 < a < m; 0 < s < m",stderr); 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: p = 0;S60:/* P = (A2*S*H)MOD M*/ if(!(a1 != 0)) goto S90; q = m/a1; k = s/q; p -= (k*(m-a1*q)); if(p > 0) p -= m; p += (a1*(s-k*q));S70: if(!(p < 0)) goto S80; p += m; goto S70;S90:S80: k = p/qh;/* P = ((A2*H + A1)*S)MOD M*/ p = h*(p-k*qh)-k*rh;S100: if(!(p < 0)) goto S110; p += m; goto S100;S120:S110: if(!(a0 != 0)) goto S150;/* P = ((A2*H + A1)*H*S)MOD M*/ q = m/a0; k = s/q; p -= (k*(m-a0*q)); if(p > 0) p -= m; p += (a0*(s-k*q));S130: if(!(p < 0)) goto S140; p += m; goto S130;S150:S140: mltmod = p; return mltmod;#undef h}void phrtsd(char* phrase,long *seed1,long *seed2)/*********************************************************************** void phrtsd(char* phrase,long *seed1,long *seed2) PHRase To SeeDs Function Uses a phrase (character string) to generate two seeds for the RGN random number generator. Arguments phrase --> Phrase to be used for random number generation seed1 <-- First seed for generator seed2 <-- Second seed for generator Note Trailing blanks are eliminated before the seeds are generated. Generated seed values will fall in the range 1..2^30 (1..1,073,741,824)***********************************************************************/{static char table[] ="abcdefghijklmnopqrstuvwxyz\ABCDEFGHIJKLMNOPQRSTUVWXYZ\0123456789\!@#$%^&*()_+[];:'\\\"<>?,./";long ix;static long twop30 = 1073741824L;static long shift[5] = { 1L,64L,4096L,262144L,16777216L};static long i,ichr,j,lphr,values[5];extern long lennob(char *str); *seed1 = 1234567890L; *seed2 = 123456789L; lphr = lennob(phrase); if(lphr < 1) return; for(i=0; i<=(lphr-1); i++) { for (ix=0; table[ix]; ix++) if (*(phrase+i) == table[ix]) break; if (!table[ix]) ix = 0; ichr = ix % 64; if(ichr == 0) ichr = 63; for(j=1; j<=5; j++) { *(values+j-1) = ichr-j; if(*(values+j-1) < 1) *(values+j-1) += 63; } for(j=1; j<=5; j++) { *seed1 = ( *seed1+*(shift+j-1)**(values+j-1) ) % twop30; *seed2 = ( *seed2+*(shift+j-1)**(values+6-j-1) ) % twop30; } }#undef twop30}float ranf(void)/*********************************************************************** float ranf(void) RANDom number generator as a Function Returns a random floating point number from a uniform distribution over 0 - 1 (endpoints of this interval are not returned) using the current generator This is a transcription from Pascal to Fortran of routine Uniform_01 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)***********************************************************************/{static float ranf;/* 4.656613057E-10 is 1/M1 M1 is set in a data statement in IGNLGI and is currently 2147483563. If M1 changes, change this also.*/ ranf = ignlgi()*4.656613057E-10; return ranf;}void setgmn(float *meanv,float *covm,long p,float *parm)/*********************************************************************** void setgmn(float *meanv,float *covm,long p,float *parm) SET Generate Multivariate Normal random deviate Function Places P, MEANV, and the Cholesky factoriztion of COVM in GENMN.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -