Normal/Gaussian random number generation for D

Joseph Rushton Wakeling joseph.wakeling at webdrake.net
Mon Oct 22 07:45:30 PDT 2012


Hello all,

A request for feedback on the design of this code before I put it through some 
serious testing and submit a formal pull request to Phobos' std.random.

The goal here is to provide an interface that is close to the Boost/C++11 design 
while allowing for some extra interesting possibilities.  In particular the goal 
is to allow the possibility of different underlying generation algorithms or 
"engines" that can serve different requirements regarding speed, precision, 
memory consumption etc.  See:
http://www.cse.cuhk.edu.hk/%7Ephwl/mt/public/archives/papers/grng_acmcs07.pdf

... for further details.

The present code contains both a function and struct interface for normal random 
number generation; the latter stores the parameters of the distribution (mean 
and standard deviation) and an instance of the underlying engine, but not the 
random number generator.

(An alternative design choice for the struct would have been to design it as a 
range with front/popFront, but for this to work I'd have had to also have it 
store the RNG, and this would run into the same problems as RandomSample has due 
to RNGs not being reference types.  Boost/C++11 also do not store the RNG 
internally but implement a variate_generator class which allows the coupling of 
a random-number distribution and an underlying generator; this is the approach 
I'd take for defining say a RandomVariate range.)

I've so far implemented one underlying engine, the Box-Muller method currently 
used in Boost.  This is not the best engine possible -- an implementation of the 
Ziggurat algorithm is desirable -- but it represents what is typically used in 
other libraries.  The essence of Box-Muller is that it generates 
(uniformly-distributed) numbers a pair at a time and then uses those to generate 
a corresponding pair of normally-distributed numbers.  The method is described here:
https://en.wikipedia.org/wiki/Box-Muller_transform

I've stuck very closely to the implementation in Boost, to the point of 
reproducing a "trick" Boost uses to get round the fact that its uniform random 
number generator only supports the interval [a, b) whereas the canonical 
description of Box-Muller requires the random numbers to be distributed in the 
interval (0, 1].  Obviously in D this is avoidable, but I felt there was some 
advantage in reproducing identical results to Boost, at least within the limits 
of floating-point numerical rounding (and maybe also because D's PI variable 
goes to a greater number of decimal places).

 From a licensing point of view this close reproduction isn't an issue, as Boost 
and Phobos both use the same licence, but there'll be a credit to the original 
Boost authors in any pull request.  However, if there's a desire to 
differentiate the code more strongly, that can be arranged :-)  I've attached a 
small C++ code example to demonstrate the common output for the D version and 
that of Boost.

Anyway, what I'd really appreciate feedback on is the interface design for these 
functions and structs.  A few concrete questions:

     (1) Does the order of template arguments seem optimal?  My inclination is 
perhaps to tweak it so that the Uniform RNG type goes first, the underlying 
engine second, and the input/output type T goes last, as these are most likely 
the order in which people will want to change things.

     (2) Is there a desire to have a separate input and output type? 
Alternatively, should I perhaps treat all input and internal processing as using 
the real type and just use T for the output?

     (3) Given the default template arguments provided, is there any way to 
ensure that an instance of the Normal struct can be implemented like this:

      auto normal01 = Normal(0, 1);

rather than having to do this:

      auto normal01 = Normal!()(0, 1);

Yes, I could create a function that returns an instance, but I'm not sure what 
to call it given that I want the normal() function to serve a similar purpose as 
uniform() ... :-)

Thanks in advance for any and all feedback.

Best wishes,

      -- Joe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: normal.d
Type: text/x-dsrc
Size: 3332 bytes
Desc: not available
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20121022/3ac454ab/attachment.d>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: boostnormal.cpp
Type: text/x-c++src
Size: 273 bytes
Desc: not available
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20121022/3ac454ab/attachment.cpp>


More information about the Digitalmars-d mailing list