clcg4.c

Go to the documentation of this file.
00001 /*
00002  *  PURPOSE
00003  *     clcg4 generator stuff
00004  *
00005  *  AUTHORS
00006  *     The following code is from L'Ecuyer and Andres "A Randow Number based
00007  *     on the combinaison of Four LCG" (distributed at the Pierre L'Ecuyer
00008  *     home page with a corresponding paper).
00009  *
00010  *  NOTES
00011  *     The original code was slightly modified by Bruno Pincon for inclusion
00012  *     in Scilab. 
00013  *
00014  *     list of main modifs :
00015  *
00016  *       - lot of routine 's names have changed to have some kind of
00017  *         uniformity with the others generators 
00018  *
00019  *       - add a var is_init so that initialisation is performed inside
00020  *         this module (to simplify the interface). And bring modif in
00021  *         the different routines :
00022  *            if (!is_init) then proceed to initialisation ...
00023  *
00024  *       - add a routine advance_state_clcg4 (for compatibility with the
00025  *         old package (Scilab used this feature))
00026  *
00027  *       - I have change the generator (clcg4 routine) so as it has the
00028  *         form (1) in place of (2) (see the joined paper of L'Ecuyer &
00029  *         Andres) :
00030  *
00031  *         From the 4 LCG :
00032  *
00033  *            x_{j,n} = a_j * x_{j,n-1} mod m_j    0 <= j <= 3
00034  *
00035  *         The output with form (2) (original form in this code) :
00036  *         
00037  *            z_n = ( sum_j  delta_j * x_{j,n} / m_j ) mod 1
00038  *
00039  *         have been changed in the form (1) :
00040  *
00041  *           z_n = ( sum_j  delta_j * x_{j,n} ) mod m_1 (then u_n = z_n / m_1)
00042  *         
00043  *         to have some "uniformity" with all the others generators (which
00044  *         gives integers). Also it is better for the uin(a,b) generation
00045  *         to start from integers.
00046  */
00047 
00048 
00049 /*---------------------------------------------------------------------*/
00050 /* clcg4.c   Implementation module                                     */
00051 /*---------------------------------------------------------------------*/
00052 
00053 #include "machine.h"
00054 #include "clcg4.h"
00055 #include <math.h>             /* for floor */
00056 #include "sciprint.h"
00057 
00058 /***********************************************************************/
00059 /* Private part.                                                       */
00060 /***********************************************************************/
00061 
00062 #define H   32768               /* = 2^15 : use in MultModM.           */
00063 
00064 static long aw[4], avw[4],      /*   a[j]^{2^w} et a[j]^{2^{v+w}}.     */
00065             a[4] = { 45991, 207707, 138556, 49689 },
00066             m[4] = { 2147483647, 2147483543, 2147483423, 2147483323 };
00067 
00068 static long Ig[4][Maxgen+1], Lg[4][Maxgen+1], Cg[4][Maxgen+1];
00069                      /* Initial seed, previous seed, and current seed. */
00070 
00071 
00072 static int  is_init = 0;
00073 static long v_default = 31;
00074 static long w_default = 41;
00075 
00076 
00077 static long MultModM (long s, long t, long M)
00078    /* Returns (s*t) MOD M.  Assumes that -M < s < M and -M < t < M.    */
00079    /* See L'Ecuyer and Cote (1991).                                    */
00080   {
00081   long R, S0, S1, q, qh, rh, k;
00082 
00083   if (s < 0)  s += M;
00084   if (t < 0)  t += M;
00085   if (s < H)  { S0 = s;  R = 0; }
00086   else
00087     {
00088     S1 = s/H;  S0 = s - H*S1;
00089     qh = M/H;  rh = M - H*qh;
00090     if (S1 >= H)
00091       {
00092       S1 -= H;   k = t/qh;   R = H * (t - k*qh) - k*rh;
00093       while (R < 0)  R += M;
00094       }
00095     else R = 0;
00096     if (S1 != 0)
00097       {
00098       q = M/S1;   k = t/q;   R -= k * (M - S1*q);
00099       if (R > 0)  R -= M;
00100       R += S1*(t - k*q);
00101       while (R < 0)  R += M;
00102       }
00103     k = R/qh;   R = H * (R - k*qh) - k*rh;
00104     while (R < 0) R += M;
00105     }
00106   if (S0 != 0)
00107     {
00108     q = M/S0;   k = t/q;   R -= k* (M - S0*q);
00109     if (R > 0)  R -= M;
00110     R += S0 * (t - k*q);
00111     while (R < 0)  R += M;
00112     }
00113   return R;
00114   }
00115 
00116 void comp_aw_and_avw(long v, long w)
00117 {
00118   int i, j;
00119   for (j = 0; j < 4; j++)
00120     {
00121       aw [j] = a [j];
00122       for (i = 1; i <= w; i++)
00123         aw [j]  = MultModM (aw [j], aw [j], m[j]);
00124       avw [j] = aw [j];
00125       for (i = 1; i <= v; i++)
00126         avw [j] = MultModM (avw [j], avw [j], m[j]);
00127     }
00128 }
00129 
00130 void init_clcg4(long v, long w)
00131 {
00132   /* currently the scilab interface don't let the user chooses
00133    * v and w (always v_default and w_default) so this routine
00134    * is in the "private" part (also because initialisation is
00135    * always perform inside this module, depending of the var
00136    * is_init)
00137    */
00138   double sd[4] = {11111111., 22222222., 33333333., 44444444.};
00139   comp_aw_and_avw(v, w);
00140   set_initial_seed_clcg4(sd[0], sd[1], sd[2], sd[3]);
00141 }
00142 
00143 int verif_seeds_clcg4(double s0, double s1, double s2, double s3)
00144 {
00145   /* verify that the seeds are "integers" and are in the good range */
00146   if ( s0 == floor(s0) && s1 == floor(s1) &&
00147        s2 == floor(s2) && s3 == floor(s3) &&
00148        1 <= s0  &&  s0 <= 2147483646      &&
00149        1 <= s1  &&  s1 <= 2147483542      &&
00150        1 <= s2  &&  s2 <= 2147483422      &&
00151        1 <= s3  &&  s3 <= 2147483322 )
00152     return ( 1 );
00153   else
00154     return ( 0 );
00155 }
00156  
00157 void display_info_clcg4()
00158 {
00159   /* display the seeds range (in case of error) */
00160   sciprint("\n\r bad seeds for clcg4, must be integers with  s1 in [1, 2147483646]");
00161   sciprint("\n\r                                             s2 in [1, 2147483542]");
00162   sciprint("\n\r                                             s3 in [1, 2147483422]");
00163   sciprint("\n\r                                             s4 in [1, 2147483322]");
00164 }
00165 
00166 
00167 /*---------------------------------------------------------------------*/
00168 /* Public part.                                                        */
00169 /*---------------------------------------------------------------------*/
00170 
00171 
00172 int set_seed_clcg4(int g, double s0, double s1, double s2, double s3)
00173 {
00174   if (! is_init ) {init_clcg4(v_default,w_default); is_init = 1; };
00175 
00176   if ( verif_seeds_clcg4(s0, s1, s2, s3) )
00177     {
00178       Ig [0][g] = (long) s0; Ig [1][g] = (long) s1;
00179       Ig [2][g] = (long) s2; Ig [3][g] = (long) s3;
00180       init_generator_clcg4(g, InitialSeed);
00181       sciprint("\n\r => be aware that you have may lost synchronization");
00182       sciprint("\n\r    between the virtual gen %d and the others !", g);
00183       sciprint("\n\r    use grand(\"setall\", s1, s2, s3, s4) if you want recover it.");
00184       return ( 1 );
00185     }
00186   else
00187     {
00188       display_info_clcg4();
00189       return ( 0 );
00190     }
00191 }
00192 
00193 void get_state_clcg4(int g, double s[4])
00194 {
00195   int j;
00196   if (! is_init ) {init_clcg4(v_default,w_default); is_init = 1; };
00197   for (j = 0; j < 4; j++)  s [j] = (double) Cg [j][g];
00198 }
00199 
00200 void init_generator_clcg4(int g, SeedType Where)
00201 {
00202   int j;
00203   if (! is_init ) {init_clcg4(v_default,w_default); is_init = 1; };
00204   for (j = 0; j < 4; j++)
00205     {
00206       switch (Where)
00207         {
00208         case InitialSeed :
00209           Lg [j][g] = Ig [j][g];   break;
00210         case NewSeed :
00211           Lg [j][g] = MultModM (aw [j], Lg [j][g], m [j]);   break;
00212         case LastSeed :
00213           break;
00214         }
00215       Cg [j][g] = Lg [j][g];
00216     }
00217 }
00218 
00219 void advance_state_clcg4(int g, int k)
00220 {
00221   long int b[4];
00222   int i, j;
00223 
00224   if (! is_init ) {init_clcg4(v_default,w_default); is_init = 1; };
00225 
00226   for ( j = 0 ; j < 4 ; j++ )
00227     {
00228       b[j] = a[j];
00229       for ( i = 1 ; i <= k ; i++ )
00230         b[j] = MultModM( b[j], b[j], m[j]);
00231       Ig[j][g] = MultModM ( b[j], Cg[j][g], m[j] );
00232     }
00233   init_generator_clcg4(g, InitialSeed);
00234 }
00235   
00236 int set_initial_seed_clcg4(double s0, double s1, double s2, double s3)
00237 {
00238   int g, j;
00239 
00240   if (! is_init )  comp_aw_and_avw(v_default,w_default);
00241 
00242   if ( ! verif_seeds_clcg4(s0, s1, s2, s3) )
00243     {
00244       display_info_clcg4();
00245       return ( 0 );
00246     };
00247 
00248   is_init = 1;
00249   Ig [0][0] = (long) s0;
00250   Ig [1][0] = (long) s1;
00251   Ig [2][0] = (long) s2;
00252   Ig [3][0] = (long) s3;
00253   init_generator_clcg4(0, InitialSeed);
00254   for (g = 1; g <= Maxgen; g++)
00255     {
00256       for (j = 0; j < 4; j++)
00257         Ig [j][g] = MultModM (avw [j], Ig [j][g-1], m [j]);
00258       init_generator_clcg4(g, InitialSeed);
00259     }
00260   return ( 1 );
00261 }
00262 
00263 unsigned long clcg4(int g)
00264 {
00265   /* Modif Bruno : the generator have now the form (1) in place of (2) */
00266 
00267   long k,s;
00268   double u;
00269 
00270   if (! is_init ) {init_clcg4(v_default,w_default); is_init = 1; };
00271 
00272   /*  advance the 4 LCG */
00273   s = Cg [0][g];  k = s / 46693;
00274   s = 45991 * (s - k * 46693) - k * 25884;
00275   if (s < 0) s = s + 2147483647;  Cg [0][g] = s;
00276  
00277   s = Cg [1][g];  k = s / 10339;
00278   s = 207707 * (s - k * 10339) - k * 870;
00279   if (s < 0) s = s + 2147483543;  Cg [1][g] = s;
00280 
00281   s = Cg [2][g];  k = s / 15499;
00282   s = 138556 * (s - k * 15499) - k * 3979;
00283   if (s < 0) s = s + 2147483423;  Cg [2][g] = s;
00284 
00285   s = Cg [3][g];  k = s / 43218;
00286   s = 49689 * (s - k * 43218) - k * 24121;
00287   if (s < 0) s = s + 2147483323;  Cg [3][g] = s;
00288 
00289   /*  final step */
00290   u = (double)(Cg[0][g] - Cg[1][g]) + (double)(Cg[2][g] - Cg[3][g]);
00291   /*  we must do  u mod 2147483647 with u in [- 4294966863 ; 4294967066 ] : */
00292   if (u < 0) u += 2147483647;
00293   if (u < 0) u += 2147483647;
00294   if (u >= 2147483647) u -= 2147483647;
00295   if (u >= 2147483647) u -= 2147483647;
00296 
00297   return ((unsigned long) u );
00298 
00299 }
00300 
00301 
00302 
00303 
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 

Generated on Sun Mar 4 15:03:59 2007 for Scilab [trunk] by  doxygen 1.5.1