Subject: [Boost-bugs] [Boost C++ Libraries] #12099: Ziggurat implementation of boost::random::exponential_distribution
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2016-03-25 20:19:59
#12099: Ziggurat implementation of boost::random::exponential_distribution
-----------------------------------------+---------------------------
Reporter: Jason Rhinelander <jason@â¦> | Owner: no-maintainer
Type: Patches | Status: new
Milestone: To Be Determined | Component: random
Version: Boost Development Trunk | Severity: Optimization
Keywords: |
-----------------------------------------+---------------------------
The Ziggurat algorithm (implemented as of boost 1.56.0 in
boost::random::normal_distribution) is suitable for any distribution with
a decreasing density (or symmetric distribution with a decreasing density
in one half, as in the case of normal_distribution). In particular the
Marsaglia and Tsang (2000) paper that described the algorithm in the first
place described both the normal distribution case and the exponential
distribution.
The attached patch (which I'll shortly also submit as a git pull request)
changes boost::random::exponential_distribution to use the Ziggurat
algorithm.
In my testing, drawing double values, this ziggurat implementation
improves the performance of the exponential distribution by about 3.9x
(debian amd64, Intel Sandy Bridge CPU, g++ 5.3.1, using -O3) to 4.4x
(debian amd64, Intel Haswell CPU, g++ 6 snapshot 20160313, using -O3).
Using -march=native in both cases increases the relative gains further (to
about 4.1x and 4.8x, respectively).
Since several other distributions rely (either directly or indirectly) on
exponential_distribution, this should have notable speed improvements for
drawing from them, as well.
This change has a couple of consequences, which are essentially the same
as the consequences that changing normal_distribution to ziggurat had (and
that some mailing list posts commented on):
- the values from an random::exponential_distribution object will change,
obviously.
- the values from dependent distributions will change (laplace, gamma,
normal, and hyperexponential, directly, plus various distributions that
make use of those).
- the RNG state can sometimes advance more than it would have before (in
particular, whenever we need to get a tail draw).
Some other comments about the details of this patch:
- I moved (without changing) the detail code for drawing an int/float pair
from random/normal_distribution.hpp into a new
random/detail/int_float_pair.hpp header, since it's needed by both the
existing normal and new exponential ziggurat implementations, and has
nothing specific to normal.
- I used a table of size 257 (versus normal's 129) so as to keep the
uniform int draw as an 8-bit value (which is what normal uses); since
exponential doesn't need a sign bit, that leaves the full 8 bits for
selecting the table index. This difference (128 vs 256) also follows
Marsaglia and Tsang's original reference implementations of normal and
exponential.
- I couldn't find an exact source for the tables in
normal_distribution.hpp, so I created a program to generate and output
them. It can reproduce either the table for exponential or normal for any
given table size; the normal output agrees *exactly* with the existing
normal_distribution tables, and the {{{table_x[1]}}} value agrees (to 13
significant digits) with the Marsaglia and Tsang reference value. I'm not
sure what to do with this program, though: is it suitable for dropping
into random/extra?
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/12099> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:19 UTC