Redefining rand and srand

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)? I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  2. I’d like to plug in my own random number generator that would probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

module Kernel
def rand(max=0)
#do random number generation magic here
end
end

But what about overriding srand(num)? srand seeds the random number
generator, so I’m assuming there is some module variable that gets set by
srand and which rand uses as well… So I figure the way to do it is
something like:

module Kernel
def rand(max=0)
generate_random(@seed)
end
def srand(seed=nil)
if not seed
#generate @seed using combiation of time, process id and sequence#
else
@seed = seed
end
end
end

…however I’m guessing that I wouldn’t have to redefine srand if I could
find the name of the module variable being used. I tried @seed, but it
wasn’t it… Kernel.instance_variables didn’t help either.

Phil

···


"Or perhaps the truth is less interesting than the facts?"
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

In article b0idhk0gj3@enews4.newsguy.com,

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)? I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  2. I’d like to plug in my own random number generator that would probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

module Kernel
def rand(max=0)
#do random number generation magic here
end
end

Here’s what I did. At Robert Feldt’s suggestion I used his RandomR
package which uses the Mersenne Twister to generate random numbers (a much
better method than whatever is built-in, I’m sure). I then redefined rand
and srand like so:

require ‘random/mersenne_twister’
module Kernel
def rand(max=0)
if not defined? @__random
@__rng=Random::MersenneTwister.new Time.now.to_i
end
@__rng.rand(max)
end
def srand(seed)
@__rng=Random::MersenneTwister.new seed
end
end

…after that everywhere I call rand it uses the Mersenne Twister rng.

Phil

···


“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

Quoteing ptkwt@shell1.aracnet.com, on Tue, Jan 21, 2003 at 12:55:13PM +0900:

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)? I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  1. I’d like to plug in my own random number generator that would probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

    if not seed
    #generate @seed using combiation of time, process id and sequence#

You may know this already, but rand() doesn’t output random numbers, it
just outputs a sequence of numbers which is statistically random.
Netscapes famous SSL security hole was caused by them seeding their
“random” number generator with time and process id, both of which are
pretty easy to guess, since they have limited ranges, and this allowed
their SSL connections to be broken.

Probably your application doesn’t need real randomness, you just want
a nice statistical spread, so this won’t affect you.

Sam

Hi,

“Phil Tomson” ptkwt@shell1.aracnet.com wrote in message
news:b0ivi80pgg@enews3.newsguy.com

In article b0idhk0gj3@enews4.newsguy.com,

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)?
    I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  2. I’d like to plug in my own random number generator that would probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

module Kernel
def rand(max=0)
#do random number generation magic here
end
end

Here’s what I did. At Robert Feldt’s suggestion I used his RandomR
package which uses the Mersenne Twister to generate random numbers (a much
better method than whatever is built-in, I’m sure). I then redefined rand
and srand like so:

require ‘random/mersenne_twister’
module Kernel
def rand(max=0)
if not defined? @__random
@__rng=Random::MersenneTwister.new Time.now.to_i
end
@__rng.rand(max)
end
def srand(seed)
@__rng=Random::MersenneTwister.new seed
end
end

How about use native Ruby code instead of extension module?
The following is my rough translation from C code(mt19937ar.c) at
http://www.math.keio.ac.jp/~matumoto/emt.html

···

=================================================================

Period parameters

N = 624
M = 397
MATRIX_A = 0x9908b0df # constant vector a
UPPER_MASK = 0x80000000 # most significant w-r bits
LOWER_MASK = 0x7fffffff # least significant r bits

static unsigned long mt[N]; # the array for the state vector

static int mti=N+1; # mti==N+1 means mt[N] is not initialized

$mt = Array.new(N)
$mti = N+1

initializes mt[N] with a seed

def init_genrand(s)
$mt[0]= s & 0xffffffff
for $mti in 1…N
$mt[$mti] =
(1812433253 * ($mt[$mti-1] ^ ($mt[$mti-1] >> 30)) + $mti)
# See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
# In the previous versions, MSBs of the seed affect
# only MSBs of the array mt.
# 2002/01/09 modified by Makoto Matsumoto
$mt[$mti] &= 0xffffffff
# for >32 bit machines
end
$mti = N
end

initialize by an array with array-length

init_key is the array for initializing keys

key_length is its length

def init_by_array(init_key, key_length)
init_genrand(19650218)
i=1
j=0
k = (N>key_length ? N : key_length)
k.downto(1) {
$mt[i] = ($mt[i] ^ (($mt[i-1] ^ ($mt[i-1] >> 30)) * 1664525)) +
init_key[j] + j # non linear
$mt[i] &= 0xffffffff # for WORDSIZE > 32 machines
i+=1
j+=1
if (i>=N)
$mt[0] = $mt[N-1]
i=1
end
if (j>=key_length)
j=0
end
}
(N-1).downto(1) {
$mt[i] = ($mt[i] ^ (($mt[i-1] ^ ($mt[i-1] >> 30)) * 1566083941)) - i

non linear

    $mt[i] &= 0xffffffff  # for WORDSIZE > 32 machines
    i+=1
    if (i>=N)
      $mt[0] = $mt[N-1]
      i=1
    end
}

$mt[0] = 0x80000000 # MSB is 1; assuring non-zero initial array

end

generates a random number on [0,0xffffffff]-interval

def genrand_int32()
mag01=[0x0, MATRIX_A]
# mag01 = x * MATRIX_A for x=0,1

if ($mti >= N)  # generate N words at one time
    if ($mti == N+1)   # if if init_genrand() has not been called,
        init_genrand(5489) # a default initial seed is used
    end

    for kk in 0...N-M
        y = ($mt[kk]&UPPER_MASK)|($mt[kk+1]&LOWER_MASK)
        $mt[kk] = $mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]
    end
    for kk in (N-M) ... (N-1)
        y = ($mt[kk]&UPPER_MASK)|($mt[kk+1]&LOWER_MASK)
        $mt[kk] = $mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]
    end
    y = ($mt[N-1]&UPPER_MASK)|($mt[0]&LOWER_MASK)
    $mt[N-1] = $mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]

    $mti = 0
end

y = $mt[$mti]
$mti+=1
y ^= (y >> 11)
y ^= (y << 7) & 0x9d2c5680
y ^= (y << 15) & 0xefc60000
y ^= (y >> 18)

return y

end

generates a random number on [0,0x7fffffff]-interval

def genrand_int31()
return (genrand_int32()>>1)
end

generates a random number on [0,1]-real-interval

def genrand_real1(void)
return genrand_int32()*(1.0/4294967295.0)
# divided by 2^32-1
end

generates a random number on [0,1)-real-interval

def genrand_real2()
return genrand_int32()*(1.0/4294967296.0)
# divided by 2^32
end

generates a random number on (0,1)-real-interval

def genrand_real3()
return (genrand_int32() + 0.5)*(1.0/4294967296.0)
# divided by 2^32
end

generates a random number on [0,1) with 53-bit resolution

def genrand_res53()
a=genrand_int32()>>5
b=genrand_int32()>>6
return (a67108864.0+b)(1.0/9007199254740992.0)
end

init=[0x123, 0x234, 0x345, 0x456]
length=4
init_by_array(init, length)

printf("1000 outputs of genrand_int32()\n")
for i in 0...1000
  printf("%10u ", genrand_int32())
  if (i%5==4)
    printf("\n")
  end
end
printf("\n1000 outputs of genrand_real2()\n")
for i in 0 ...1000
  printf("%10.8f ", genrand_real2())
  if (i%5==4)
    printf("\n")
  end
end

=====================================================

Park Heesob

In article 20030122034335.GA10142@debian,

Quoteing ptkwt@shell1.aracnet.com, on Tue, Jan 21, 2003 at 12:55:13PM +0900:

You may know this already, but rand() doesn’t output random numbers, it
just outputs a sequence of numbers which is statistically random.

Right, pseudo-random. Isn’t there a VonNeumann quote where he says
something like “those who try to generate randomness using deterministic
means are seriously deluded…” (or some such)

Netscapes famous SSL security hole was caused by them seeding their
“random” number generator with time and process id, both of which are
pretty easy to guess, since they have limited ranges, and this allowed
their SSL connections to be broken.

Probably your application doesn’t need real randomness, you just want
a nice statistical spread, so this won’t affect you.

There are no security implications to what I’m doing…

Now if you want real random numbers you can get them from
http://random.org

Hal Fulton has an example in “The Ruby Way” that shows how to fetch random
numbers from that site.

Phil

···

Sam Roberts sroberts@uniserve.com wrote:

“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

How about use native Ruby code instead of extension module?
The following is my rough translation from C code(mt19937ar.c) at
http://www.math.keio.ac.jp/~matumoto/emt.html

1.8 use Mersenne Twister

Guy Decoux

In article b0j1t4$77$1@news.hananet.net,

Hi,

“Phil Tomson” ptkwt@shell1.aracnet.com wrote in message
news:b0ivi80pgg@enews3.newsguy.com

In article b0idhk0gj3@enews4.newsguy.com,

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)?
    I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  2. I’d like to plug in my own random number generator that would probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

module Kernel
def rand(max=0)
#do random number generation magic here
end
end

Here’s what I did. At Robert Feldt’s suggestion I used his RandomR
package which uses the Mersenne Twister to generate random numbers (a much
better method than whatever is built-in, I’m sure). I then redefined rand
and srand like so:

require ‘random/mersenne_twister’
module Kernel
def rand(max=0)
if not defined? @__rng
@__rng=Random::MersenneTwister.new Time.now.to_i
end
@__rng.rand(max)
end
def srand(seed)
@__rng=Random::MersenneTwister.new seed
end
end

How about use native Ruby code instead of extension module?
The following is my rough translation from C code(mt19937ar.c) at
http://www.math.keio.ac.jp/~matumoto/emt.html

C code is faster… I’m using this for a genetic algorithms class.
20 runs of 200 generations each on a 28bit chromosome is taking about 5
minutes right now as it is. If I use a pure Ruby RNG that’s gonna get
slower… However I’m going to experiment later with a RNG based on
cellular automata that I don’t think would be significantly slower in Ruby
vs. C (the next-state calculations are just hash lookups).

Thanks for the code, though.

Phil

···

Park Heesob phasis@nownuri.net wrote:


“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

Here it is, cited in the Perl Cookbook. It’s a classic!

Anyone who considers arithmetical methods of producing
random digits is, of course, in a state of sin.

             -- John von Neumann (1951)
···

On Wednesday, January 22, 2003, 4:59:46 PM, Phil wrote:

You may know this already, but rand() doesn’t output random numbers, it
just outputs a sequence of numbers which is statistically random.

Right, pseudo-random. Isn’t there a VonNeumann quote where he says
something like “those who try to generate randomness using deterministic
means are seriously deluded…” (or some such)

Hi,

“Phil Tomson” ptkwt@shell1.aracnet.com wrote in message
news:b0ivi80pgg@enews3.newsguy.com
In article b0idhk0gj3@enews4.newsguy.com,

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)?
    I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  2. I’d like to plug in my own random number generator that would
    probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

module Kernel
def rand(max=0)
#do random number generation magic here
end
end

So long as we’re redefining rand, and srand, can I recommend that they
be put into a Random object? It is occasionally very helpful to have
separate random number domains. Especially when you’re trying to abuse
a PRNG.

···

On Tuesday, January 21, 2003, at 03:15 AM, Park Heesob wrote:

Judson Lester wrote:

So long as we’re redefining rand, and srand, can I recommend that they
be put into a Random object? It is occasionally very helpful to have
separate random number domains. Especially when you’re trying to abuse
a PRNG.

I second that. I’ve done it for myself using Numerical Recipes
generators, but those have a license fee. I’d very much like to have
multiple PRNG streams built in to ruby.

Hi,

A couple of questions:

  1. how good is Ruby’s rand function (what’s the quality of randomness)? I
    suspec that it is just the same as C’s rand, so there won’t be a
    difference.
  2. I’d like to plug in my own random number generator that would
    probably
    produce higher-quality random numbers than the current rand does. I’m
    pretty sure it should be doable and easy, like:

module Kernel
def rand(max=0)
#do random number generation magic here
end
end

So long as we’re redefining rand, and srand, can I recommend that they
be put into a Random object? It is occasionally very helpful to have
separate random number domains. Especially when you’re trying to
abuse a PRNG.

Tried.

There are Random and Random::MT classes, former is the
interface and stub, and latter is an implementation. All
methods of MT are internal, and RNG classes must implement the
first 3 methods (initialize, seed, next) and should do the last
(copy_object).

— Random::seed
generates appropriate seed integer.

— Random::default, Random::default=
accessor for default RNG class. defaulted to Random::MT.

— Random::current, Random::current=
accessor for current RNG instance. never returns nil.

— Random#rand([max=nil])
returns next random value.

— Random::MT#initialize([seed=nil])
returns seed value.

— Random::MT#seed
returns seed value.

— Random::MT#next
returns next random value as Float.

— Random::MT#copy_object(obj)
copies the content from obj.

Calling Random#next as method would make rand() much slower,

but “fast method call” (mentioned in [ruby-dev:19781] a

little) might be efficient.

random-obj.diff.gz (2.43 KB)

···

At Sat, 22 Mar 2003 03:30:00 +0900, Judson Lester wrote:

Hi,

Tried.

I’ve forgot this.

— random.c~ 22 Mar 2003 01:30:54 -0000
+++ random.c 23 Mar 2003 08:03:52 -0000
@@ -142,12 +142,13 @@

#include “ruby.h”

+static VALUE mt_alloc _((VALUE));
static VALUE
mt_alloc(klass)
VALUE klass;
{
struct MT *mt;

  • VALUE obj = Data_Make_Struct(obj, struct MT, 0, xfree, mt);
  • VALUE obj = Data_Make_Struct(klass, struct MT, 0, -1, mt);
    mt->left = 1;
    return obj;
    }
···

At Sat, 22 Mar 2003 10:33:10 +0900, nobu.nokada@softhome.net wrote:


Nobu Nakada