Rand() needs a seed?

I’m a noob Ruby user, but IronRuby behaves different from other Ruby
implementations that I’ve tried, in IronRuby (rev 121) this code:

100.times {p rand(100)}

Often returns the same value for (almost) all iterations, like this:

2
2
2
2
2
2
2
2
…and so on…

Works as designed? Need to seed it or something?

/Johan

By default, the parameterless constructor of the System.Random class
(which is what we’re using) uses the system time as the initial seed.
Every time you ask for a random number, we create a new Random object,
and in a tight loop like yours, they’ll probably all get the same seed.

We should probably create a single Random object the first time that one
is requested and store it in the RubyContext.

From: [email protected]
[mailto:[email protected]] On Behalf Of Johan Danforth
Sent: Sunday, July 06, 2008 7:28 AM
To: [email protected]
Subject: [Ironruby-core] rand() needs a seed?

I’m a noob Ruby user, but IronRuby behaves different from other Ruby
implementations that I’ve tried, in IronRuby (rev 121) this code:

100.times {p rand(100)}

Often returns the same value for (almost) all iterations, like this:

2
2
2
2
2
2
2
2
…and so on…

Works as designed? Need to seed it or something?

/Johan

Like this?

private static readonly Random rndGen = new Random();

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static double Rand(CodeContext/!/ context, object self) {
lock(rndGen) return rndGen.NextDouble();
}

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static object Rand(CodeContext/!/ context, object self, int
limit) {
if (limit == 0) return Rand(context, self);
lock (rndGen) return
RuntimeHelpers.Int32ToObject((int)(rndGen.NextDouble() * (limit - 1)));
}

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static object Rand(CodeContext/!/ context, object self, double
limit) {
if (limit < 1) return Rand(context, self);
lock (rndGen) return
RuntimeHelpers.Int32ToObject((int)(rndGen.NextDouble() * (limit - 1)));
}

I put a lock() on each call as well, because I believe the Next-methods
aren’t thread safe. Works for me.

/Johan

From: [email protected]
[mailto:[email protected]] On Behalf Of Curt
Hagenlocher
Sent: den 6 juli 2008 17:16
To: [email protected]
Subject: Re: [Ironruby-core] rand() needs a seed?

By default, the parameterless constructor of the System.Random class
(which is what we’re using) uses the system time as the initial seed.
Every time you ask for a random number, we create a new Random object,
and in a tight loop like yours, they’ll probably all get the same seed.

We should probably create a single Random object the first time that one
is requested and store it in the RubyContext.

From: [email protected]
[mailto:[email protected]] On Behalf Of Johan Danforth
Sent: Sunday, July 06, 2008 7:28 AM
To: [email protected]
Subject: [Ironruby-core] rand() needs a seed?

I’m a noob Ruby user, but IronRuby behaves different from other Ruby
implementations that I’ve tried, in IronRuby (rev 121) this code:

100.times {p rand(100)}

Often returns the same value for (almost) all iterations, like this:

2
2
2
2
2
2
2
2
…and so on…

Works as designed? Need to seed it or something?

/Johan

Something like that, yes, but making it a static member of KernelOps
means that we have to pay the construction cost during startup. For a
function as infrequently used as “rand”, it might be better to
initialize it more lazily.

From: [email protected]
[mailto:[email protected]] On Behalf Of Johan Danforth
Sent: Sunday, July 06, 2008 9:51 AM
To: [email protected]
Subject: Re: [Ironruby-core] rand() needs a seed?

Like this?

private static readonly Random rndGen = new Random();

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static double Rand(CodeContext/!/ context, object self) {
lock(rndGen) return rndGen.NextDouble();
}

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static object Rand(CodeContext/!/ context, object self, int
limit) {
if (limit == 0) return Rand(context, self);
lock (rndGen) return
RuntimeHelpers.Int32ToObject((int)(rndGen.NextDouble() * (limit - 1)));
}

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static object Rand(CodeContext/!/ context, object self, double
limit) {
if (limit < 1) return Rand(context, self);
lock (rndGen) return
RuntimeHelpers.Int32ToObject((int)(rndGen.NextDouble() * (limit - 1)));
}

I put a lock() on each call as well, because I believe the Next-methods
aren’t thread safe. Works for me.

/Johan

From: [email protected]
[mailto:[email protected]] On Behalf Of Curt
Hagenlocher
Sent: den 6 juli 2008 17:16
To: [email protected]
Subject: Re: [Ironruby-core] rand() needs a seed?

By default, the parameterless constructor of the System.Random class
(which is what we’re using) uses the system time as the initial seed.
Every time you ask for a random number, we create a new Random object,
and in a tight loop like yours, they’ll probably all get the same seed.

We should probably create a single Random object the first time that one
is requested and store it in the RubyContext.

From: [email protected]
[mailto:[email protected]] On Behalf Of Johan Danforth
Sent: Sunday, July 06, 2008 7:28 AM
To: [email protected]
Subject: [Ironruby-core] rand() needs a seed?

I’m a noob Ruby user, but IronRuby behaves different from other Ruby
implementations that I’ve tried, in IronRuby (rev 121) this code:

100.times {p rand(100)}

Often returns the same value for (almost) all iterations, like this:

2
2
2
2
2
2
2
2
…and so on…

Works as designed? Need to seed it or something?

/Johan

Note there is also srand() method that seeds the generator. The
generator therefore needs to be associated with RubyExecutionContext.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Curt
Hagenlocher
Sent: Sunday, July 06, 2008 11:49 AM
To: [email protected]
Subject: Re: [Ironruby-core] rand() needs a seed?

Something like that, yes, but making it a static member of KernelOps
means that we have to pay the construction cost during startup. For a
function as infrequently used as “rand”, it might be better to
initialize it more lazily.

From: [email protected]
[mailto:[email protected]] On Behalf Of Johan Danforth
Sent: Sunday, July 06, 2008 9:51 AM
To: [email protected]
Subject: Re: [Ironruby-core] rand() needs a seed?

Like this?

private static readonly Random rndGen = new Random();

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static double Rand(CodeContext/!/ context, object self) {
lock(rndGen) return rndGen.NextDouble();
}

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static object Rand(CodeContext/!/ context, object self, int
limit) {
if (limit == 0) return Rand(context, self);
lock (rndGen) return
RuntimeHelpers.Int32ToObject((int)(rndGen.NextDouble() * (limit - 1)));
}

[RubyMethod(“rand”, RubyMethodAttributes.PrivateInstance)]
[RubyMethod(“rand”, RubyMethodAttributes.PublicSingleton)]
public static object Rand(CodeContext/!/ context, object self, double
limit) {
if (limit < 1) return Rand(context, self);
lock (rndGen) return
RuntimeHelpers.Int32ToObject((int)(rndGen.NextDouble() * (limit - 1)));
}

I put a lock() on each call as well, because I believe the Next-methods
aren’t thread safe. Works for me.

/Johan

From: [email protected]
[mailto:[email protected]] On Behalf Of Curt
Hagenlocher
Sent: den 6 juli 2008 17:16
To: [email protected]
Subject: Re: [Ironruby-core] rand() needs a seed?

By default, the parameterless constructor of the System.Random class
(which is what we’re using) uses the system time as the initial seed.
Every time you ask for a random number, we create a new Random object,
and in a tight loop like yours, they’ll probably all get the same seed.

We should probably create a single Random object the first time that one
is requested and store it in the RubyContext.

From: [email protected]
[mailto:[email protected]] On Behalf Of Johan Danforth
Sent: Sunday, July 06, 2008 7:28 AM
To: [email protected]
Subject: [Ironruby-core] rand() needs a seed?

I’m a noob Ruby user, but IronRuby behaves different from other Ruby
implementations that I’ve tried, in IronRuby (rev 121) this code:

100.times {p rand(100)}

Often returns the same value for (almost) all iterations, like this:

2
2
2
2
2
2
2
2
…and so on…

Works as designed? Need to seed it or something?

/Johan