Opened 7 years ago

Last modified 7 years ago

#12099 new Patches

Ziggurat implementation of boost::random::exponential_distribution

Reported by: Jason Rhinelander <jason@…> Owned by: No-Maintainer
Milestone: To Be Determined Component: random
Version: Boost Development Trunk Severity: Optimization
Keywords: Cc:

Description

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?

Attachments (3)

0001-Implement-ziggurat-for-exponential-random-dist.patch (24.9 KB ) - added by Jason Rhinelander <jason@…> 7 years ago.
patch: ziggurat for exponential_distribution
rexp_tables.cpp (4.5 KB ) - added by Jason Rhinelander <jason@…> 7 years ago.
normal and exponential table generator
scratch.cpp (20.5 KB ) - added by Steven Watanabe 7 years ago.
Source for the tables used by boost::random::normal_distribution

Download all attachments as: .zip

Change History (4)

by Jason Rhinelander <jason@…>, 7 years ago

patch: ziggurat for exponential_distribution

by Jason Rhinelander <jason@…>, 7 years ago

Attachment: rexp_tables.cpp added

normal and exponential table generator

comment:1 by Steven Watanabe, 7 years ago

I've tracked down the program that I used to generate the tables.

by Steven Watanabe, 7 years ago

Attachment: scratch.cpp added

Source for the tables used by boost::random::normal_distribution

Note: See TracTickets for help on using tickets.