Normal/Gaussian random number generation for D

Joseph Rushton Wakeling joseph.wakeling at webdrake.net
Wed Oct 24 03:22:01 PDT 2012


On 10/23/2012 04:36 PM, jerro wrote:
> I have an implementation of the Ziggurat algorithm at
> https://github.com/jerro/phobos/blob/master/std/random.d#L2035.

OK, so I had a reasonable (not totally in-depth!) look through.  Looks good! 
And of course reminds of the other benefit of Ziggurat, that it can be used for 
multiple different random number distributions.

It looks like it should be readily possible to integrate the core Ziggurat 
functionality and to convert the normal() function in your code to be a 
NormalRandomNumberEngine struct -- so assuming you like my own architecture 
proposal, let's do this (I'm happy to hear suggestions for alternative designs, 
as I don't feel particularly confident in my API-designing abilities).

For the other distributions, my feeling is that in some cases there's a value in 
also having this "engine" approach, e.g. for exponentially-distributed numbers 
one could use Ziggurat or one could use the approach

     T u = uniform!("[)", T, T, UniformRandomNumberGenerator)(0.0, 1.0, urng);
     return -log(1 - u)/lambda;

... which is not as fast but has a much lower memory footprint.

> It modified the Ziggurat algorithm a bit, so that it doesn't need as many layers
> to work well, which reduces the memory consumption and makes initialization faster.

Can you expand on this, and maybe provide a reference?  I don't doubt your 
code's effectiveness but I think where RNGs are concerned we really need to be 
able to justify our algorithmic choices.  There's too much literature out there 
showing how commonly-used algorithms actually carry statistical flaws.

Bigger picture on my approach to non-uniform random number distributions.  The 
goal is to have the following:

     * Where useful, it should be possible to define and use multiple different
       internal "engines" for generating random numbers from the given
       distribution

     * For each distribution, there should be a function interface and a struct
       interface.

     * The struct implementation should store the distribution parameters and an
       instance of the internal engine (if any).

     * The function implementation should have 2 versions: one which allows the
       user to pass an engine of choice as input, one which contains a static
       instance of the specified engine (hence, thread-safe, distinguished
       according to both engine type and underlying uniform RNG type).

     * ... unless there's no call for distinct underlying engines, in which case
       the function version just takes parameters and uniform RNG :-)

     * The struct version should be useful to couple with an RNG instance to
       create an arbitrary random-number range à la Boost's variate_generator
       class.

So, a nice way to expand on our respective approaches might be to incorporate 
your Ziggurat, adapt it to my Normal engine API, and for me to write a similar 
setup for exponentially-distributed random numbers that uses the simple approach 
above and can also use your Ziggurat implementation.

What do you think?

Best wishes,

     -- Joe


More information about the Digitalmars-d mailing list