00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #define N 624
00065 #define M 397
00066 #define MATRIX_A 0x9908b0dfUL
00067 #define UMASK 0x80000000UL
00068 #define LMASK 0x7fffffffUL
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];
00073 static int left = 1;
00074 static int initf = 0;
00075 static unsigned long *next;
00076
00077
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
00087
00088
00089
00090 state[j] &= 0xffffffffUL;
00091 }
00092 left = 1; initf = 1;
00093 }
00094
00095
00096
00097
00098
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;
00109 state[i] &= 0xffffffffUL;
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;
00117 state[i] &= 0xffffffffUL;
00118 i++;
00119 if (i>=N) { state[0] = state[N-1]; i=1; }
00120 }
00121
00122 state[0] = 0x80000000UL;
00123 left = 1; initf = 1;
00124 }
00125
00126 static void
00127 next_state()
00128 {
00129 unsigned long *p=state;
00130 int j;
00131
00132
00133
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
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
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
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
00174
00175 #undef N
00176 #undef M
00177
00178
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;
00219 buf = ALLOC_N(unsigned long, len);
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)
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
00303 digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0;
00304
00305 return rb_big_norm((VALUE)big);
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
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
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
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
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
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