default random object?

dsimcha dsimcha at yahoo.com
Fri Feb 13 18:37:35 PST 2009


== Quote from Andrei Alexandrescu (SeeWebsiteForEmail at erdani.org)'s article
> Leonardo suggested that some functions in std.random should not require
> their user to be bothered with creating a random object, i.e.:
> auto r = Random(unpredictableSeed);
> auto n = uniform(r, 0, 100);
> Instead the library should simply support:
> auto n = uniform(0, 100);
> and do this by presumably using a global RNG under the hood. So I wanted
> to ask all y'all:
> 1. Are you cool with making the rng the last parameter and give it a
> default value?

Yes.

> 2. The global random generator will be allocated per thread. Are you
> cool with this too?

Yes.  I've found D2's random number generation scheme somewhat annoying up until
now because it requires the caller to explicitly do something with the underlying
RNG object between random number generations, in a sense lessening the
encapsulation of the higher level random number generation functions such as
uniform() and stuff that's written by the user. Even if you make a Uniform object
or a Normal object or something, the implementation detail that pseudorandom
number generation requires state to be maintained in between calls still leaks out
into the interface.  IMHO, the whole concept of RNGs requiring state to be
maintained between calls is an implementation detail and therefore should ideally
be encapsulated.

For small, single-threaded programs, most of the time I just declare a global RNG
and seed it in a module initializer anyhow, for convenience.  This thread-local
RNG is a perfect way to provide a simple default behavior that "just works" and is
well-encapsulated, while still allowing more flexibility and control in the
relatively rare cases when it's really needed.

> 3. How should the global rng be initialized? To always generate the same
> sequence, or not?

It should be properly seeded, though I don't know how this would work for RNGs for
anything but the main thread.  This keeps with the principle that the default
should "just work" reasonably well without the user having to think about
implementation details.  Maybe core.thread.Thread needs to have the ability to
execute a callback function on the creation of a new thread.  This is probably not
a bad feature anyhow.

> 4. While we're at it, should uniform(a, b) generate by default something
> in [a, b] or [a, b)? Someone once explained to me that generating [a, b]
> for floating point numbers is the source of all evils and that Hitler,
> Stalin and Kim Il Sung (should he still be alive) must be using that
> kind of generator. Conversely, generating [a, b) is guaranteed to bring
> in the long term everlasting peace to Earth. My problem however is that
> in the integer realm I always want to generate [a, b]. Furthermore, I
> wouldn't be happy if the shape of the interval was different for
> integers and floating point numbers. How to break this conundrum? Don't
> forget that we're only worrying about defaults, explicit generation is
> always possible with self-explanatory code:
> auto rng = Random(unpredictableSeed);
> auto a = 0.0, b = 1.0;
> auto x1 = uniform!("[]")(rng, a, b);
> auto x2 = uniform!("[)")(rng, a, b);
> auto x3 = uniform!("(]")(rng, a, b);
> auto x4 = uniform!("()")(rng, a, b);

I like uniform the way it is, [a, b), even for integers, because it jives well
with array slice notation, and a major use for uniform integers is randomly
selecting an element from an array.  This is not that important, though, because
no matter what you do, it's going to seem stupid and unintuitive to someone.




More information about the Digitalmars-d mailing list