summaryrefslogtreecommitdiff
path: root/random.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-07-26 06:12:39 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-07-26 06:12:39 +0000
commit7194b66fb24db63dc2a23d3141ce25ad85d89777 (patch)
tree6e4a442522711c87eb3fc61bf81efc90af356394 /random.c
parent1d132e648dff057f0a5b42ddbc3704e7816213fc (diff)
downloadruby-7194b66fb24db63dc2a23d3141ce25ad85d89777.tar.gz
* random.c: replace with Mersenne Twister RNG.
* eval.c (jump_tag_but_local_jump): preserve retval in LocalJumpError exceptions. * parse.y (command): no more check for "super outside of method". * eval.c (rb_mod_define_method): should set last_class and last_func in the block->frame. * eval.c (error_handle): should handle TAG_THROW as well. * parse.y (yylex): new decimal notation '0d4567'. * parse.y (yylex): new octal notation '0o777'. * parse.y (string_content): every string_content node should return string only. use NODE_EVSTR to coercing. * eval.c (rb_eval): NODE_EVSTR support. * re.c (rb_reg_quote): avoid unnecessary string allocation. * string.c (get_pat): quote metachracters before compiling a string into a regex. * string.c (rb_str_split_m): special treatment of strings of size 1, but AWK emulation. now uses get_pat(). * string.c (rb_str_match_m): quote metacharacters. * string.c (rb_str_match2): ditto. * ext/socket/socket.c (sock_addrinfo): make all 3 versions of getaddrinfo happy. [ruby-core:00184] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2654 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'random.c')
-rw-r--r--random.c235
1 files changed, 155 insertions, 80 deletions
diff --git a/random.c b/random.c
index 3fdac4a5c4..6b6d5d7045 100644
--- a/random.c
+++ b/random.c
@@ -10,6 +10,131 @@
**********************************************************************/
+/*
+This is based on trimmed version of MT19937. To get the original version,
+contact <http://www.math.keio.ac.jp/~matumoto/emt.html>.
+
+The original copyright notice follows.
+
+ A C-program for MT19937, with initialization improved 2002/2/10.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+ This is a faster version by taking Shawn Cokus's optimization,
+ Matthe Bellew's simplification, Isaku Wada's real version.
+
+ Before using, initialize the state by using init_genrand(seed)
+ or init_by_array(init_key, key_length).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ Any feedback is very welcome.
+ http://www.math.keio.ac.jp/matumoto/emt.html
+ email: matumoto@math.keio.ac.jp
+*/
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+#define UMASK 0x80000000UL /* most significant w-r bits */
+#define LMASK 0x7fffffffUL /* least significant r bits */
+#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
+#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
+
+static unsigned long state[N]; /* the array for the state vector */
+static int left = 1;
+static int initf = 0;
+static unsigned long *next;
+
+/* initializes state[N] with a seed */
+static void
+init_genrand(s)
+ unsigned long s;
+{
+ int j;
+ state[0]= s & 0xffffffffUL;
+ for (j=1; j<N; j++) {
+ state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array state[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ state[j] &= 0xffffffffUL; /* for >32 bit machines */
+ }
+ left = 1; initf = 1;
+}
+
+static void
+next_state()
+{
+ unsigned long *p=state;
+ int j;
+
+ /* if init_genrand() has not been called, */
+ /* a default initial seed is used */
+ if (initf==0) init_genrand(5489UL);
+
+ left = N;
+ next = state;
+
+ for (j=N-M+1; --j; p++)
+ *p = p[M] ^ TWIST(p[0], p[1]);
+
+ for (j=M; --j; p++)
+ *p = p[M-N] ^ TWIST(p[0], p[1]);
+
+ *p = p[M-N] ^ TWIST(p[0], state[0]);
+}
+
+/* generates a random number on [0,1)-real-interval */
+static double
+genrand_real()
+{
+ unsigned long y;
+
+ if (--left == 0) next_state();
+ y = *next++;
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return (double)y * (1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/* These real versions are due to Isaku Wada, 2002/01/09 added */
+
#include "ruby.h"
#ifdef HAVE_UNISTD_H
@@ -27,84 +152,33 @@ struct timeval {
#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 */
-
-/* 0 <= RANDOM_NUMBER < 1 */
-#define RANDOM_NUMBER (((double)RANDOM())/((double)RANDOM_MAX+1))
-
-#endif /* not HAVE_DRAND48 */
-
static int first = 1;
-#ifdef HAVE_INITSTATE
-static char state[256];
-#endif
static int
rand_init(seed)
- long seed;
+ unsigned long seed;
{
- int old;
- static unsigned int saved_seed;
+ static unsigned long saved_seed;
+ unsigned long old;
-#ifdef HAVE_INITSTATE
- if (first == 1) {
- initstate(1, state, sizeof state);
- }
- else {
- setstate(state);
- }
-#endif
first = 0;
-
- SRANDOM(seed);
+ init_genrand(seed);
old = saved_seed;
saved_seed = seed;
return old;
}
+static unsigned long
+random_seed()
+{
+ static int n = 0;
+ struct timeval tv;
+
+ gettimeofday(&tv, 0);
+ return tv.tv_sec ^ tv.tv_usec ^ getpid() ^ n++;
+}
+
static VALUE
rb_f_srand(argc, argv, obj)
int argc;
@@ -112,18 +186,14 @@ rb_f_srand(argc, argv, obj)
VALUE obj;
{
VALUE sd;
- unsigned int seed, old;
+ unsigned long seed, old;
rb_secure(4);
if (rb_scan_args(argc, argv, "01", &sd) == 0) {
- static int n = 0;
- struct timeval tv;
-
- gettimeofday(&tv, 0);
- seed = tv.tv_sec ^ tv.tv_usec ^ getpid() ^ n++;
+ seed = random_seed();
}
else {
- seed = NUM2UINT(sd);
+ seed = NUM2ULONG(sd);
}
old = rand_init(seed);
@@ -141,10 +211,7 @@ rb_f_rand(argc, argv, obj)
rb_scan_args(argc, argv, "01", &vmax);
if (first) {
- struct timeval tv;
-
- gettimeofday(&tv, 0);
- rand_init(tv.tv_sec ^ tv.tv_usec ^ getpid());
+ rand_init(random_seed());
}
switch (TYPE(vmax)) {
case T_FLOAT:
@@ -155,7 +222,15 @@ rb_f_rand(argc, argv, obj)
vmax = rb_dbl2big(RFLOAT(vmax)->value);
/* fall through */
case T_BIGNUM:
- return rb_big_rand(vmax, RANDOM_NUMBER);
+ {
+ long len = RBIGNUM(vmax)->len;
+ double *buf = ALLOCA_N(double, len);
+
+ while (len--) {
+ buf[len] = genrand_real();
+ }
+ return rb_big_rand(vmax, buf);
+ }
case T_NIL:
max = 0;
break;
@@ -165,11 +240,11 @@ rb_f_rand(argc, argv, obj)
}
if (max == 0) {
- return rb_float_new(RANDOM_NUMBER);
+ return rb_float_new(genrand_real());
}
- val = max*RANDOM_NUMBER;
+ if (max < 0) max = -max;
+ val = max*genrand_real();
- if (val < 0) val = -val;
return LONG2NUM(val);
}