Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mdp_prng.h

Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00027 class mdp_prng {
00028  private:
00029   float u[98];
00030   float c;
00031   float cd;
00032   float cm;
00033   int ui;
00034   int uj;
00035 public:
00037   inline float plain() {
00038     float luni;                 /* local variable for Float */      
00039     luni = u[ui] - u[uj];
00040     if (luni < 0.0)
00041       luni += 1.0;
00042     u[ui] = luni;
00043     if (--ui == 0)
00044       ui = 97;
00045     if (--uj == 0)
00046       uj = 97;
00047     if ((c -= cd) < 0.0)
00048       c += cm;
00049     if ((luni -= c) < 0.0)
00050       luni += 1.0;
00051     return ((float) luni);
00052   }
00053 
00055   //      initializei: this takes a single integer in the range
00056   //            0 <= ijkl <= 900 000 000
00057   //    and produces the four smaller integers needed for start. It is
00058   //    based on the ideas contained in the RMARIN subroutine in
00059   //            F. James, "A Review of Pseudorandom Number Generators",
00060   //                    Comp. Phys. Commun. Oct 1990, p.340
00061   //    To reduce the modifications to the existing code, seed_uni now
00062   //    takes the role of a preprocessor for rstart.
00063   //
00064   //    This is useful for the parallel version of the code as James
00065   //    states that any integer ijkl will produce a statistically
00066   //    independent sequence of random numbers.
00067   //
00068   //     Very funny. 
00069   //     If that statement was worth anything he would have provided
00070   //     a proof to go with it. spb 12/12/90 
00072 
00073   void initialize(long ijkl) {
00074     int i, j, k, l, ij, kl;
00075     if( (ijkl < 0) || (ijkl > 900000000) )
00076       error("Wrong initialization for random number generator");
00077     ij = ijkl/30082;
00078     kl = ijkl - (30082 * ij);
00079     i = ((ij/177) % 177) + 2;
00080     j = (ij % 177) + 2;
00081     k = ((kl/169) % 178) + 1;
00082     l = kl % 169;
00083     if( (i <= 0) || (i > 178) )
00084       error("Wrong initialization for random number generator");        
00085     if( (j <= 0) || (j > 178) )
00086       error("Wrong initialization for random number generator");        
00087     if( (k <= 0) || (k > 178) )
00088       error("Wrong initialization for random number generator");        
00089     if( (l < 0) || (l > 168) )
00090       error("Wrong initialization for random number generator");        
00091     if (i == 1 && j == 1 && k == 1)
00092       error("Wrong initialization for random number generator");        
00093     int ii, jj, m;
00094     float s, t;
00095     for (ii = 1; ii <= 97; ii++) {
00096       s = 0.0;
00097       t = 0.5;
00098       for (jj = 1; jj <= 24; jj++) {
00099         m = ((i*j % 179) * k) % 179;
00100         i = j;
00101         j = k;
00102         k = m;
00103         l = (53*l+1) % 169;
00104         if (l*m % 64 >= 32) s += t;
00105         t *= 0.5;
00106       }
00107       u[ii] = s;
00108     }
00109     c  = 362436.0   / 16777216.0;
00110     cd = 7654321.0  / 16777216.0;
00111     cm = 16777213.0 / 16777216.0;
00112     ui = 97; /*  There is a bug in the original Fortran version */
00113     uj = 33; /*  of UNI -- i and j should be SAVEd in UNI()     */
00114   }
00115   mdp_prng(long k=0) {
00116     if(k==0) initialize(ME);
00117   }
00119   float gaussian(float sigma=1) {
00120 #ifdef AIX
00121     static int i; // assumes i is set to zero by default
00122 #else
00123     static int i=0;
00124 #endif
00125     static float r;
00126     float x,y;
00127     if(i==0) {
00128       x=(float) sqrt(-2.0*log(plain()));
00129       y=(float) 2.0*Pi*plain();
00130       i=1;
00131       r=sigma*x*((float) cos(y));
00132       return sigma*x*((float) sin(y));
00133     } else {
00134       i=0;
00135       return r;
00136     }
00137   }
00139   double distribution(float (*fp)(float, void *), void *a=0) {
00140     float x,y;
00141     do {
00142       x=plain();
00143       y=plain();
00144     } while ((*fp)(x, a)>=y);
00145     return x;
00146   }
00148   mdp_matrix SU(int n) {
00149     mdp_matrix tmp, small;
00150     register int i,j;
00151     register float alpha, sin_alpha;
00152     register float a0, a1, a2, a3;
00153     register float phi, cos_theta, sin_theta;
00154     if(n==1) { 
00155       tmp.dimension(1,1);
00156       alpha=2.0*Pi*this->plain();
00157         tmp(0,0)=mdp_complex(cos(alpha),sin(alpha));
00158       return tmp;
00159     }
00160     tmp=mdp_identity(n);
00161     for(i=0; i<(n-1); i++)
00162       for(j=i+1; j<n; j++) {
00163         alpha=Pi*this->plain(); 
00164         phi=2.0*Pi*this->plain();
00165         cos_theta=2.0*this->plain()-1.0;
00166         sin_theta=sqrt(1.0-cos_theta*cos_theta);
00167         sin_alpha=sin(alpha);
00168         a0=cos(alpha);
00169         a1=sin_alpha*sin_theta*cos(phi);
00170         a2=sin_alpha*sin_theta*sin(phi);
00171         a3=sin_alpha*cos_theta;
00172         small=mdp_identity(n);
00173         small(i,i)=mdp_complex(a0,a3);
00174         small(i,j)=mdp_complex(a2,a1);
00175         small(j,i)=mdp_complex(-a2,a1);
00176         small(j,j)=mdp_complex(a0,-a3);
00177         tmp=small*tmp;
00178       }
00179     return tmp;
00180   }
00182   void skip(int n) {
00183     for(int i=0; i<n; i++) this->plain();
00184   }
00185 } mdp_random; 

Generated on Sun Feb 27 15:12:21 2005 by  doxygen 1.4.1