2000-05-01 05:42:38 -04:00
|
|
|
/**********************************************************************
|
1998-01-16 07:13:05 -05:00
|
|
|
|
|
|
|
random.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
$Date$
|
|
|
|
created at: Fri Dec 24 16:39:21 JST 1993
|
|
|
|
|
2001-02-14 00:52:06 -05:00
|
|
|
Copyright (C) 1993-2001 Yukihiro Matsumoto
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2000-05-01 05:42:38 -04:00
|
|
|
**********************************************************************/
|
1998-01-16 07:13:05 -05:00
|
|
|
|
|
|
|
#include "ruby.h"
|
|
|
|
|
1999-09-01 05:48:03 -04:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
1999-01-19 23:59:39 -05:00
|
|
|
#include <time.h>
|
|
|
|
#ifndef NT
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
# include <sys/time.h>
|
|
|
|
#else
|
|
|
|
struct timeval {
|
|
|
|
long tv_sec; /* seconds */
|
|
|
|
long tv_usec; /* and microseconds */
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif /* NT */
|
|
|
|
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
|
|
# include <stdlib.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prefer to use drand48, otherwise use random, or rand as a last resort.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_DRAND48
|
|
|
|
|
|
|
|
#ifndef HAVE_DRAND48_DECL
|
|
|
|
double drand48 _((void));
|
|
|
|
void srand48 _((long));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define SRANDOM(s) srand48((long)(s))
|
|
|
|
#define RANDOM_NUMBER drand48()
|
|
|
|
|
|
|
|
#else /* not HAVE_DRAND48 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The largest number returned by the random number generator is
|
|
|
|
* RANDOM_MAX. If we're using `rand' it's RAND_MAX, but if we're
|
|
|
|
* using `random' it's 2^31-1.
|
|
|
|
*/
|
|
|
|
#ifndef RANDOM_MAX
|
|
|
|
# ifndef HAVE_RANDOM
|
|
|
|
# define RANDOM_MAX RAND_MAX
|
|
|
|
# else
|
|
|
|
# define RANDOM_MAX 2147483647.0
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_RANDOM
|
|
|
|
|
|
|
|
#define RANDOM random
|
|
|
|
#define SRANDOM srandom
|
|
|
|
|
|
|
|
#else /* HAVE_RANDOM */
|
|
|
|
|
|
|
|
#define RANDOM rand
|
|
|
|
#define SRANDOM srand
|
|
|
|
|
|
|
|
#endif /* HAVE_RANDOM */
|
|
|
|
|
2000-08-03 05:50:41 -04:00
|
|
|
/* 0 <= RANDOM_NUMBER < 1 */
|
1999-08-13 01:45:20 -04:00
|
|
|
#define RANDOM_NUMBER (((double)RANDOM())/((double)RANDOM_MAX+1))
|
1999-01-19 23:59:39 -05:00
|
|
|
|
|
|
|
#endif /* not HAVE_DRAND48 */
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
static int first = 1;
|
2000-02-08 03:54:01 -05:00
|
|
|
#ifdef HAVE_RANDOM
|
1998-01-16 07:13:05 -05:00
|
|
|
static char state[256];
|
1999-01-19 23:59:39 -05:00
|
|
|
#endif
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2000-01-08 00:00:25 -05:00
|
|
|
static int
|
|
|
|
rand_init(seed)
|
|
|
|
long seed;
|
|
|
|
{
|
|
|
|
int old;
|
|
|
|
static unsigned int saved_seed;
|
|
|
|
|
2002-02-26 23:30:20 -05:00
|
|
|
#if defined HAVE_RANDOM && !defined __UCLIBC__
|
2000-01-08 00:00:25 -05:00
|
|
|
if (first == 1) {
|
|
|
|
initstate(1, state, sizeof state);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
setstate(state);
|
|
|
|
}
|
|
|
|
#endif
|
2000-01-17 03:37:53 -05:00
|
|
|
first = 0;
|
2000-01-08 00:00:25 -05:00
|
|
|
|
|
|
|
SRANDOM(seed);
|
|
|
|
old = saved_seed;
|
|
|
|
saved_seed = seed;
|
|
|
|
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
static VALUE
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_f_srand(argc, argv, obj)
|
1998-01-16 07:13:05 -05:00
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE obj;
|
|
|
|
{
|
1999-10-27 00:20:14 -04:00
|
|
|
VALUE a;
|
|
|
|
unsigned int seed, old;
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2000-11-14 02:10:31 -05:00
|
|
|
rb_secure(4);
|
1999-10-27 00:20:14 -04:00
|
|
|
if (rb_scan_args(argc, argv, "01", &a) == 0) {
|
1999-09-16 05:40:33 -04:00
|
|
|
static int n = 0;
|
1999-01-19 23:59:39 -05:00
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
gettimeofday(&tv, 0);
|
1999-09-16 05:40:33 -04:00
|
|
|
seed = tv.tv_sec ^ tv.tv_usec ^ getpid() ^ n++;
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
else {
|
1999-10-27 00:20:14 -04:00
|
|
|
seed = NUM2UINT(a);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
2000-01-08 00:00:25 -05:00
|
|
|
old = rand_init(seed);
|
1998-01-16 07:13:05 -05:00
|
|
|
|
1999-10-27 00:20:14 -04:00
|
|
|
return rb_uint2inum(old);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2000-07-04 00:17:26 -04:00
|
|
|
rb_f_rand(argc, argv, obj)
|
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE obj;
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2000-07-04 00:17:26 -04:00
|
|
|
VALUE vmax;
|
1999-01-19 23:59:39 -05:00
|
|
|
long val, max;
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2000-07-04 00:17:26 -04:00
|
|
|
rb_scan_args(argc, argv, "01", &vmax);
|
2000-01-08 00:00:25 -05:00
|
|
|
if (first) {
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
gettimeofday(&tv, 0);
|
|
|
|
rand_init(tv.tv_sec ^ tv.tv_usec ^ getpid());
|
|
|
|
}
|
1998-01-16 07:13:05 -05:00
|
|
|
switch (TYPE(vmax)) {
|
|
|
|
case T_FLOAT:
|
2000-11-02 04:04:54 -05:00
|
|
|
if (RFLOAT(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) {
|
|
|
|
max = (long)RFLOAT(vmax)->value;
|
1999-12-06 04:04:03 -05:00
|
|
|
break;
|
2000-11-02 04:04:54 -05:00
|
|
|
}
|
|
|
|
vmax = rb_dbl2big(RFLOAT(vmax)->value);
|
1999-12-06 04:04:03 -05:00
|
|
|
/* fall through */
|
|
|
|
case T_BIGNUM:
|
|
|
|
return rb_big_rand(vmax, RANDOM_NUMBER);
|
2000-07-04 00:17:26 -04:00
|
|
|
case T_NIL:
|
|
|
|
max = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
max = NUM2LONG(vmax);
|
|
|
|
break;
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
if (max == 0) {
|
|
|
|
return rb_float_new(RANDOM_NUMBER);
|
|
|
|
}
|
|
|
|
val = max*RANDOM_NUMBER;
|
1998-01-16 07:13:05 -05:00
|
|
|
|
|
|
|
if (val < 0) val = -val;
|
1999-01-19 23:59:39 -05:00
|
|
|
return rb_int2inum(val);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Init_Random()
|
|
|
|
{
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_define_global_function("srand", rb_f_srand, -1);
|
2000-07-04 00:17:26 -04:00
|
|
|
rb_define_global_function("rand", rb_f_rand, -1);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|