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