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

I already have a NormalDist struct at https://github.com/jerro/phobos/blob/new-api/std/random.d#L2363 - converting that should be trivial.


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.

I agree that the it's a good thing to design the API so that we can use different engines

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.

I have only tested a distribution of the output samples, which seems to be correct. I agree that we should try to avoid statistical flaws as much as possible. Do you know of any good tests for nonuniform random number generators?

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.

Seems OK to me. Maybe the function that uses a static engine should have one version that takes Rng as a parameter and one that uses rndGen, similar to how uniform() works now?

How would the static engines be initialized? They could be initialized on first use, but this would slow sample generation a bit. Another options is to initialize them in the static constructor. I think it would be best to make the engine a static field of a struct template, and initialize it in the structs static constructor (similar to what my ZigguratTable struct does). That way you don't need to check if the engine is initialized every time you generate a sample and the engine isn't initialized unless the function template that uses it is instantiated.

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?

I think we should do that. Do you already have some code somewhere where I can see it? I need to know what API the NormalRandomNumberEngine struct should have.

Reply via email to