Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

random.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   random.c -
00004 
00005   $Author: nobu $
00006   $Date: 2005/02/12 06:07:47 $
00007   created at: Fri Dec 24 16:39:21 JST 1993
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
00010 
00011 **********************************************************************/
00012 
00013 /* 
00014 This is based on trimmed version of MT19937.  To get the original version,
00015 contact <http://www.math.keio.ac.jp/~matumoto/emt.html>.
00016 
00017 The original copyright notice follows.
00018 
00019    A C-program for MT19937, with initialization improved 2002/2/10.
00020    Coded by Takuji Nishimura and Makoto Matsumoto.
00021    This is a faster version by taking Shawn Cokus's optimization,
00022    Matthe Bellew's simplification, Isaku Wada's real version.
00023 
00024    Before using, initialize the state by using init_genrand(seed) 
00025    or init_by_array(init_key, key_length).
00026 
00027    Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
00028    All rights reserved.                          
00029 
00030    Redistribution and use in source and binary forms, with or without
00031    modification, are permitted provided that the following conditions
00032    are met:
00033 
00034      1. Redistributions of source code must retain the above copyright
00035         notice, this list of conditions and the following disclaimer.
00036 
00037      2. Redistributions in binary form must reproduce the above copyright
00038         notice, this list of conditions and the following disclaimer in the
00039         documentation and/or other materials provided with the distribution.
00040 
00041      3. The names of its contributors may not be used to endorse or promote 
00042         products derived from this software without specific prior written 
00043         permission.
00044 
00045    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00046    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00047    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00048    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00049    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00050    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00051    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00052    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00053    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00054    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00055    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00056 
00057 
00058    Any feedback is very welcome.
00059    http://www.math.keio.ac.jp/matumoto/emt.html
00060    email: matumoto@math.keio.ac.jp
00061 */
00062 
00063 /* Period parameters */  
00064 #define N 624
00065 #define M 397
00066 #define MATRIX_A 0x9908b0dfUL   /* constant vector a */
00067 #define UMASK 0x80000000UL /* most significant w-r bits */
00068 #define LMASK 0x7fffffffUL /* least significant r bits */
00069 #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
00070 #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
00071 
00072 static unsigned long state[N]; /* the array for the state vector  */
00073 static int left = 1;
00074 static int initf = 0;
00075 static unsigned long *next;
00076 
00077 /* initializes state[N] with a seed */
00078 static void
00079 init_genrand(s)
00080     unsigned long s;
00081 {
00082     int j;
00083     state[0]= s & 0xffffffffUL;
00084     for (j=1; j<N; j++) {
00085         state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j); 
00086         /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
00087         /* In the previous versions, MSBs of the seed affect   */
00088         /* only MSBs of the array state[].                        */
00089         /* 2002/01/09 modified by Makoto Matsumoto             */
00090         state[j] &= 0xffffffffUL;  /* for >32 bit machines */
00091     }
00092     left = 1; initf = 1;
00093 }
00094 
00095 /* initialize by an array with array-length */
00096 /* init_key is the array for initializing keys */
00097 /* key_length is its length */
00098 /* slight change for C++, 2004/2/26 */
00099 static void
00100 init_by_array(unsigned long init_key[], int key_length)
00101 {
00102     int i, j, k;
00103     init_genrand(19650218UL);
00104     i=1; j=0;
00105     k = (N>key_length ? N : key_length);
00106     for (; k; k--) {
00107         state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525UL))
00108           + init_key[j] + j; /* non linear */
00109         state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
00110         i++; j++;
00111         if (i>=N) { state[0] = state[N-1]; i=1; }
00112         if (j>=key_length) j=0;
00113     }
00114     for (k=N-1; k; k--) {
00115         state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL))
00116           - i; /* non linear */
00117         state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
00118         i++;
00119         if (i>=N) { state[0] = state[N-1]; i=1; }
00120     }
00121 
00122     state[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ 
00123     left = 1; initf = 1;
00124 }
00125 
00126 static void
00127 next_state()
00128 {
00129     unsigned long *p=state;
00130     int j;
00131 
00132     /* if init_genrand() has not been called, */
00133     /* a default initial seed is used         */
00134     if (initf==0) init_genrand(5489UL);
00135 
00136     left = N;
00137     next = state;
00138     
00139     for (j=N-M+1; --j; p++) 
00140         *p = p[M] ^ TWIST(p[0], p[1]);
00141 
00142     for (j=M; --j; p++) 
00143         *p = p[M-N] ^ TWIST(p[0], p[1]);
00144 
00145     *p = p[M-N] ^ TWIST(p[0], state[0]);
00146 }
00147 
00148 /* generates a random number on [0,0xffffffff]-interval */
00149 static unsigned long
00150 genrand_int32(void)
00151 {
00152     unsigned long y;
00153 
00154     if (--left == 0) next_state();
00155     y = *next++;
00156 
00157     /* Tempering */
00158     y ^= (y >> 11);
00159     y ^= (y << 7) & 0x9d2c5680UL;
00160     y ^= (y << 15) & 0xefc60000UL;
00161     y ^= (y >> 18);
00162 
00163     return y;
00164 }
00165 
00166 /* generates a random number on [0,1) with 53-bit resolution*/
00167 static double
00168 genrand_real(void) 
00169 { 
00170     unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; 
00171     return(a*67108864.0+b)*(1.0/9007199254740992.0); 
00172 } 
00173 /* These real versions are due to Isaku Wada, 2002/01/09 added */
00174 
00175 #undef N
00176 #undef M
00177 
00178 /* These real versions are due to Isaku Wada, 2002/01/09 added */
00179 
00180 #include "ruby.h"
00181 
00182 #ifdef HAVE_UNISTD_H
00183 #include <unistd.h>
00184 #endif
00185 #include <time.h>
00186 #include <sys/types.h>
00187 #include <sys/stat.h>
00188 #ifdef HAVE_FCNTL_H
00189 #include <fcntl.h>
00190 #endif
00191 
00192 static int first = 1;
00193 static VALUE saved_seed = INT2FIX(0);
00194 
00195 static VALUE
00196 rand_init(vseed)
00197     VALUE vseed;
00198 {
00199     volatile VALUE seed;
00200     VALUE old;
00201     long len;
00202     unsigned long *buf;
00203 
00204     seed = rb_to_int(vseed);
00205     switch (TYPE(seed)) {
00206       case T_FIXNUM:
00207           len = sizeof(VALUE);
00208           break;
00209       case T_BIGNUM:
00210           len = RBIGNUM(seed)->len * SIZEOF_BDIGITS;
00211           if (len == 0)
00212               len = 4;
00213           break;
00214       default:
00215           rb_raise(rb_eTypeError, "failed to convert %s into Integer",
00216                    rb_obj_classname(vseed));
00217     }
00218     len = (len + 3) / 4; /* number of 32bit words */
00219     buf = ALLOC_N(unsigned long, len); /* allocate longs for init_by_array */
00220     memset(buf, 0, len * sizeof(long));
00221     if (FIXNUM_P(seed)) {
00222         buf[0] = FIX2ULONG(seed) & 0xffffffff;
00223 #if SIZEOF_LONG > 4
00224         buf[1] = FIX2ULONG(seed) >> 32;
00225 #endif
00226     }
00227     else {
00228         int i, j;
00229         for (i = RBIGNUM(seed)->len-1; 0 <= i; i--) {
00230             j = i * SIZEOF_BDIGITS / 4;
00231 #if SIZEOF_BDIGITS < 4
00232             buf[j] <<= SIZEOF_BDIGITS * 8;
00233 #endif
00234             buf[j] |= ((BDIGIT *)RBIGNUM(seed)->digits)[i];
00235         }
00236     }
00237     while (1 < len && buf[len-1] == 0) {
00238         len--;
00239     }
00240     if (len <= 1) {
00241         init_genrand(buf[0]);
00242     }
00243     else {
00244         if (buf[len-1] == 1) /* remove leading-zero-guard */
00245             len--;
00246         init_by_array(buf, len);
00247     }
00248     first = 0;
00249     old = saved_seed;
00250     saved_seed = seed;
00251     free(buf);
00252     return old;
00253 }
00254 
00255 static VALUE
00256 random_seed()
00257 {
00258     static int n = 0;
00259     struct timeval tv;
00260     int fd;
00261     struct stat statbuf;
00262 
00263     int seed_len;
00264     BDIGIT *digits;
00265     unsigned long *seed;
00266     NEWOBJ(big, struct RBignum);
00267     OBJSETUP(big, rb_cBignum, T_BIGNUM);
00268 
00269     seed_len = 4 * sizeof(long);
00270     big->sign = 1;
00271     big->len = seed_len / SIZEOF_BDIGITS + 1;
00272     digits = big->digits = ALLOC_N(BDIGIT, big->len);
00273     seed = (unsigned long *)big->digits;
00274 
00275     memset(digits, 0, big->len * SIZEOF_BDIGITS);
00276 
00277 #ifdef S_ISCHR
00278     if ((fd = open("/dev/urandom", O_RDONLY
00279 #ifdef O_NONBLOCK
00280             |O_NONBLOCK
00281 #endif
00282 #ifdef O_NOCTTY
00283             |O_NOCTTY
00284 #endif
00285 #ifdef O_NOFOLLOW
00286             |O_NOFOLLOW
00287 #endif
00288             )) >= 0) {
00289         if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
00290             read(fd, seed, seed_len);
00291         }
00292         close(fd);
00293     }
00294 #endif
00295 
00296     gettimeofday(&tv, 0);
00297     seed[0] ^= tv.tv_usec;
00298     seed[1] ^= tv.tv_sec;
00299     seed[2] ^= getpid() ^ (n++ << 16);
00300     seed[3] ^= (unsigned long)&seed;
00301 
00302     /* set leading-zero-guard if need. */
00303     digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0;
00304 
00305     return rb_big_norm((VALUE)big);
00306 }
00307 
00308 /*
00309  *  call-seq:
00310  *     srand(number=0)    => old_seed
00311  *  
00312  *  Seeds the pseudorandom number generator to the value of
00313  *  <i>number</i>.<code>to_i.abs</code>. If <i>number</i> is omitted
00314  *  or zero, seeds the generator using a combination of the time, the
00315  *  process id, and a sequence number. (This is also the behavior if
00316  *  <code>Kernel::rand</code> is called without previously calling
00317  *  <code>srand</code>, but without the sequence.) By setting the seed
00318  *  to a known value, scripts can be made deterministic during testing.
00319  *  The previous seed value is returned. Also see <code>Kernel::rand</code>.
00320  */
00321 
00322 static VALUE
00323 rb_f_srand(argc, argv, obj)
00324     int argc;
00325     VALUE *argv;
00326     VALUE obj;
00327 {
00328     VALUE seed, old;
00329 
00330     rb_secure(4);
00331     if (rb_scan_args(argc, argv, "01", &seed) == 0) {
00332         seed = random_seed();
00333     }
00334     old = rand_init(seed);
00335 
00336     return old;
00337 }
00338 
00339 static unsigned long 
00340 make_mask(unsigned long x)
00341 {
00342     x = x | x >> 1;
00343     x = x | x >> 2;
00344     x = x | x >> 4;
00345     x = x | x >> 8;
00346     x = x | x >> 16;
00347 #if 4 < SIZEOF_LONG
00348     x = x | x >> 32;
00349 #endif
00350     return x;
00351 }
00352 
00353 static unsigned long
00354 limited_rand(unsigned long limit)
00355 {
00356     unsigned long mask = make_mask(limit);
00357     int i;
00358     unsigned long val;
00359 
00360   retry:
00361     val = 0;
00362     for (i = SIZEOF_LONG/4-1; 0 <= i; i--) {
00363         if (mask >> (i * 32)) {
00364             val |= genrand_int32() << (i * 32);
00365             val &= mask;
00366             if (limit < val)
00367                 goto retry;
00368         }
00369     }
00370     return val;
00371 }
00372 
00373 static VALUE
00374 limited_big_rand(struct RBignum *limit)
00375 {
00376     unsigned long mask, lim, rnd;
00377     struct RBignum *val;
00378     int i, len, boundary;
00379 
00380     len = (limit->len * SIZEOF_BDIGITS + 3) / 4;
00381     val = (struct RBignum *)rb_big_clone((VALUE)limit);
00382     val->sign = 1;
00383 #if SIZEOF_BDIGITS == 2
00384 # define BIG_GET32(big,i) (((BDIGIT *)(big)->digits)[(i)*2] | \
00385                            ((i)*2+1 < (big)->len ? (((BDIGIT *)(big)->digits)[(i)*2+1] << 16) \
00386                                                  : 0))
00387 # define BIG_SET32(big,i,d) ((((BDIGIT *)(big)->digits)[(i)*2] = (d) & 0xffff), \
00388                              ((i)*2+1 < (big)->len ? (((BDIGIT *)(big)->digits)[(i)*2+1] = (d) >> 16) \
00389                                                    : 0))
00390 #else
00391     /* SIZEOF_BDIGITS == 4 */
00392 # define BIG_GET32(big,i) (((BDIGIT *)(big)->digits)[i])
00393 # define BIG_SET32(big,i,d) (((BDIGIT *)(big)->digits)[i] = (d))
00394 #endif
00395   retry:
00396     mask = 0;
00397     boundary = 1;
00398     for (i = len-1; 0 <= i; i--) {
00399         lim = BIG_GET32(limit, i);
00400         mask = mask ? 0xffffffff : make_mask(lim);
00401         if (mask) {
00402             rnd = genrand_int32() & mask;
00403             if (boundary) {
00404                 if (lim < rnd)
00405                     goto retry;
00406                 if (rnd < lim)
00407                     boundary = 0;
00408             }
00409         }
00410         else {
00411             rnd = 0;
00412         }
00413         BIG_SET32(val, i, rnd);
00414     }
00415     return rb_big_norm((VALUE)val);
00416 }
00417 
00418 /*
00419  *  call-seq:
00420  *     rand(max=0)    => number
00421  *  
00422  *  Converts <i>max</i> to an integer using max1 =
00423  *  max<code>.to_i.abs</code>. If the result is zero, returns a
00424  *  pseudorandom floating point number greater than or equal to 0.0 and
00425  *  less than 1.0. Otherwise, returns a pseudorandom integer greater
00426  *  than or equal to zero and less than max1. <code>Kernel::srand</code>
00427  *  may be used to ensure repeatable sequences of random numbers between
00428  *  different runs of the program. Ruby currently uses a modified
00429  *  Mersenne Twister with a period of 219937-1.
00430  *     
00431  *     srand 1234                 #=> 0
00432  *     [ rand,  rand ]            #=> [0.191519450163469, 0.49766366626136]
00433  *     [ rand(10), rand(1000) ]   #=> [6, 817]
00434  *     srand 1234                 #=> 1234
00435  *     [ rand,  rand ]            #=> [0.191519450163469, 0.49766366626136]
00436  */
00437 
00438 static VALUE
00439 rb_f_rand(argc, argv, obj)
00440     int argc;
00441     VALUE *argv;
00442     VALUE obj;
00443 {
00444     VALUE vmax;
00445     long val, max;
00446 
00447     rb_scan_args(argc, argv, "01", &vmax);
00448     if (first) {
00449         rand_init(random_seed());
00450     }
00451     switch (TYPE(vmax)) {
00452       case T_FLOAT:
00453         if (RFLOAT(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) {
00454             max = (long)RFLOAT(vmax)->value;
00455             break;
00456         }
00457         if (RFLOAT(vmax)->value < 0)
00458             vmax = rb_dbl2big(-RFLOAT(vmax)->value);
00459         else
00460             vmax = rb_dbl2big(RFLOAT(vmax)->value);
00461         /* fall through */
00462       case T_BIGNUM:
00463       bignum:
00464         {
00465             struct RBignum *limit = (struct RBignum *)vmax;
00466             if (!limit->sign) {
00467                 limit = (struct RBignum *)rb_big_clone(vmax);
00468                 limit->sign = 1;
00469             }
00470             limit = (struct RBignum *)rb_big_minus((VALUE)limit, INT2FIX(1));
00471             if (FIXNUM_P((VALUE)limit)) {
00472                 if (FIX2LONG((VALUE)limit) == -1)
00473                     return rb_float_new(genrand_real());
00474                 return LONG2NUM(limited_rand(FIX2LONG((VALUE)limit)));
00475             }
00476             return limited_big_rand(limit);
00477         }
00478       case T_NIL:
00479         max = 0;
00480         break;
00481       default:
00482         vmax = rb_Integer(vmax);
00483         if (TYPE(vmax) == T_BIGNUM) goto bignum;
00484       case T_FIXNUM:
00485         max = FIX2LONG(vmax);
00486         break;
00487     }
00488 
00489     if (max == 0) {
00490         return rb_float_new(genrand_real());
00491     }
00492     if (max < 0) max = -max;
00493     val = limited_rand(max-1);
00494     return LONG2NUM(val);
00495 }
00496 
00497 void
00498 Init_Random()
00499 {
00500     rb_define_global_function("srand", rb_f_srand, -1);
00501     rb_define_global_function("rand", rb_f_rand, -1);
00502     rb_global_variable(&saved_seed);
00503 }
00504 

Generated on Wed Jan 18 23:32:05 2006 for Ruby by doxygen 1.3.5