From c2d8ffb6f6511b4ad6b751c90cce4d3cc3fa559c Mon Sep 17 00:00:00 2001 From: nobody Date: Fri, 23 Jul 2004 02:16:28 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'SPIRIT_1_6'. [SVN r23968] --- histogram.cpp | 170 -- index.html | 161 -- integrate.hpp | 84 - nondet_random.html | 131 -- nondet_random_speed.cpp | 69 - random-concepts.html | 429 ----- random-distributions.html | 796 --------- random-generators.html | 1038 ----------- random-misc.html | 93 - random-performance.html | 241 --- random-variate.html | 144 -- random_demo.cpp | 133 -- random_device.cpp | 122 -- random_speed.cpp | 371 ---- random_test.cpp | 539 ------ statistic_tests.cpp | 669 ------- statistic_tests.hpp | 643 ------- test/Jamfile | 25 - test/Jamfile.v2 | 20 - wg21-proposal.html | 3518 ------------------------------------- 20 files changed, 9396 deletions(-) delete mode 100644 histogram.cpp delete mode 100644 index.html delete mode 100644 integrate.hpp delete mode 100644 nondet_random.html delete mode 100644 nondet_random_speed.cpp delete mode 100644 random-concepts.html delete mode 100644 random-distributions.html delete mode 100644 random-generators.html delete mode 100644 random-misc.html delete mode 100644 random-performance.html delete mode 100644 random-variate.html delete mode 100644 random_demo.cpp delete mode 100644 random_device.cpp delete mode 100644 random_speed.cpp delete mode 100644 random_test.cpp delete mode 100644 statistic_tests.cpp delete mode 100644 statistic_tests.hpp delete mode 100644 test/Jamfile delete mode 100644 test/Jamfile.v2 delete mode 100644 wg21-proposal.html diff --git a/histogram.cpp b/histogram.cpp deleted file mode 100644 index 053961b..0000000 --- a/histogram.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* boost histogram.cpp graphical verification of distribution functions - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - * This test program allows to visibly examine the results of the - * distribution functions. - */ - -#include -#include -#include -#include -#include -#include -#include - - -void plot_histogram(const std::vector& slots, int samples, - double from, double to) -{ - int m = *std::max_element(slots.begin(), slots.end()); - const int nRows = 20; - std::cout.setf(std::ios::fixed|std::ios::left); - std::cout.precision(5); - for(int r = 0; r < nRows; r++) { - double y = ((nRows - r) * double(m))/(nRows * samples); - std::cout << std::setw(10) << y << " "; - for(unsigned int col = 0; col < slots.size(); col++) { - char out = ' '; - if(slots[col]/double(samples) >= y) - out = 'x'; - std::cout << out; - } - std::cout << std::endl; - } - std::cout << std::setw(12) << " " - << std::setw(10) << from; - std::cout.setf(std::ios::right, std::ios::adjustfield); - std::cout << std::setw(slots.size()-10) << to << std::endl; -} - -// I am not sure whether these two should be in the library as well - -// maintain sum of NumberGenerator results -template -class sum_result -{ -public: - typedef NumberGenerator base_type; - typedef typename base_type::result_type result_type; - explicit sum_result(const base_type & g) : gen(g), _sum(0) { } - result_type operator()() { result_type r = gen(); _sum += r; return r; } - base_type & base() { return gen; } - Sum sum() const { return _sum; } - void reset() { _sum = 0; } -private: - base_type gen; - Sum _sum; -}; - - -// maintain square sum of NumberGenerator results -template -class squaresum_result -{ -public: - typedef NumberGenerator base_type; - typedef typename base_type::result_type result_type; - explicit squaresum_result(const base_type & g) : gen(g), _sum(0) { } - result_type operator()() { result_type r = gen(); _sum += r*r; return r; } - base_type & base() { return gen; } - Sum squaresum() const { return _sum; } - void reset() { _sum = 0; } -private: - base_type gen; - Sum _sum; -}; - - -template -void histogram(RNG base, int samples, double from, double to, - const std::string & name) -{ - typedef squaresum_result, double > SRNG; - SRNG gen((sum_result(base))); - const int nSlots = 60; - std::vector slots(nSlots,0); - for(int i = 0; i < samples; i++) { - double val = gen(); - if(val < from || val >= to) // early check avoids overflow - continue; - int slot = int((val-from)/(to-from) * nSlots); - if(slot < 0 || slot > (int)slots.size()) - continue; - slots[slot]++; - } - std::cout << name << std::endl; - plot_histogram(slots, samples, from, to); - double mean = gen.base().sum() / samples; - std::cout << "mean: " << mean - << " sigma: " << std::sqrt(gen.squaresum()/samples-mean*mean) - << "\n" << std::endl; -} - -template -inline boost::variate_generator make_gen(PRNG & rng, Dist d) -{ - return boost::variate_generator(rng, d); -} - -template -void histograms() -{ - PRNG rng; - using namespace boost; - histogram(make_gen(rng, uniform_smallint<>(0, 5)), 100000, -1, 6, - "uniform_smallint(0,5)"); - histogram(make_gen(rng, uniform_int<>(0, 5)), 100000, -1, 6, - "uniform_int(0,5)"); - histogram(make_gen(rng, uniform_real<>(0,1)), 100000, -0.5, 1.5, - "uniform_real(0,1)"); - histogram(make_gen(rng, bernoulli_distribution<>(0.2)), 100000, -0.5, 1.5, - "bernoulli(0.2)"); - histogram(make_gen(rng, binomial_distribution<>(4, 0.2)), 100000, -1, 5, - "binomial(4, 0.2)"); - histogram(make_gen(rng, triangle_distribution<>(1, 2, 8)), 100000, 0, 10, - "triangle(1,2,8)"); - histogram(make_gen(rng, geometric_distribution<>(5.0/6.0)), 100000, 0, 10, - "geometric(5/6)"); - histogram(make_gen(rng, exponential_distribution<>(0.3)), 100000, 0, 10, - "exponential(0.3)"); - histogram(make_gen(rng, cauchy_distribution<>()), 100000, -5, 5, - "cauchy"); - histogram(make_gen(rng, lognormal_distribution<>(3, 2)), 100000, 0, 10, - "lognormal"); - histogram(make_gen(rng, normal_distribution<>()), 100000, -3, 3, - "normal"); - histogram(make_gen(rng, normal_distribution<>(0.5, 0.5)), 100000, -3, 3, - "normal(0.5, 0.5)"); - histogram(make_gen(rng, poisson_distribution<>(1.5)), 100000, 0, 5, - "poisson(1.5)"); - histogram(make_gen(rng, poisson_distribution<>(10)), 100000, 0, 20, - "poisson(10)"); - histogram(make_gen(rng, gamma_distribution<>(0.5)), 100000, 0, 0.5, - "gamma(0.5)"); - histogram(make_gen(rng, gamma_distribution<>(1)), 100000, 0, 3, - "gamma(1)"); - histogram(make_gen(rng, gamma_distribution<>(2)), 100000, 0, 6, - "gamma(2)"); -} - - -int main() -{ - histograms(); - // histograms(); -} - diff --git a/index.html b/index.html deleted file mode 100644 index 84e4cca..0000000 --- a/index.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - -Boost Random Number Library - - - - - - - - - - - - - -
c++boost.gif (8819 bytes)HomeLibrariesPeopleFAQMore
- -

Boost Random Number Library

- -Random numbers are useful in a variety of applications. The Boost -Random Number Library (Boost.Random for short) provides a vast variety -of generators and distributions to produce random numbers having -useful properties, such as uniform distribution. -

-You should read the -concepts documentation -for an introduction and the definition of the basic concepts. For a -quick start, it may be sufficient to have a look at random_demo.cpp. -

-For a very quick start, here's an example: -

-  boost::mt19937 rng;                 // produces randomness out of thin air
-                                      // see pseudo-random number generators
-  boost::uniform_int<> six(1,6)       // distribution that maps to 1..6
-                                      // see random number distributions
-  boost::variate_generator<boost::mt19937, boost::uniform_int<> >
-           die(rng, six);             // glues randomness with mapping
-  int x = die();                      // simulate rolling a die
-
- -

Library Organization

- -The library is separated into several header files, all within the -boost/random/ directory. Additionally, a convenience -header file which includes all other headers in -boost/random/ is available as -boost/random.hpp. -

- -A front-end class template called variate_generate is -provided; please read the -documentation about it. -

- -Several random number generators are available in the following -header files; please read the -documentation about these. - - - - -Similarly, several random number distributions are available in the -following header files; please read the -documentation about these. - - - -Additionally, non-deterministic random number generators are available -in the header -<boost/nondet_random.hpp>. -Documentation is also available. - -

- -In order to map the interface of the generators and distribution functions -to other concepts, some decorators are available. - -

Tests

- -An extensive test suite for the pseudo-random number generators and -distributions is available as -random_test.cpp. -

-Some performance results obtained -using random_speed.cpp are also available. - -

Rationale

- -The methods for generating and evaluating deterministic and -non-deterministic random numbers differ radically. Furthermore, due -to the inherent deterministic design of present-day computers, it is -often difficult to implement non-deterministic random number -generation facilities. Thus, the random number library is split into -separate header files, mirroring the two different application -domains. - - -

History and Acknowledgements

- -In November 1999, Jeet Sukumaran proposed a framework based on virtual -functions, and later sketched a template-based approach. Ed Brey -pointed out that Microsoft Visual C++ does not support in-class member -initializations and suggested the enum workaround. Dave -Abrahams highlighted quantization issues. -

-The first public release of this random number library materialized in -March 2000 after extensive discussions on the boost mailing list. -Many thanks to Beman Dawes for his original min_rand -class, portability fixes, documentation suggestions, and general -guidance. Harry Erwin sent a header file which provided additional -insight into the requirements. Ed Brey and Beman Dawes wanted an -iterator-like interface. -

-Beman Dawes managed the formal review, during which Matthias Troyer, -Csaba Szepesvari, and Thomas Holenstein gave detailed comments. The -reviewed version became an official part of boost on 17 June 2000. -

-Gary Powell contributed suggestions for code cleanliness. Dave -Abrahams and Howard Hinnant suggested to move the basic generator -templates from namespace boost::detail to -boost::random. -

-Ed Brey asked to remove superfluous warnings and helped with -uint64_t handling. Andreas Scherer tested with MSVC. -Matthias Troyer contributed a lagged Fibonacci generator. Michael -Stevens found a bug in the copy semantics of normal_distribution and -suggested documentation improvements. -

-


-Jens Maurer, -2001-08-31 - - - diff --git a/integrate.hpp b/integrate.hpp deleted file mode 100644 index c637f35..0000000 --- a/integrate.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* integrate.hpp header file - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - * Revision history - * 01 April 2001: Modified to use new header. (JMaddock) - */ - -#ifndef INTEGRATE_HPP -#define INTEGRATE_HPP - -#include - -template -inline typename UnaryFunction::result_type -trapezoid(UnaryFunction f, typename UnaryFunction::argument_type a, - typename UnaryFunction::argument_type b, int n) -{ - typename UnaryFunction::result_type tmp = 0; - for(int i = 1; i <= n-1; ++i) - tmp += f(a+(b-a)/n*i); - return (b-a)/2/n * (f(a) + f(b) + 2*tmp); -} - -template -inline typename UnaryFunction::result_type -simpson(UnaryFunction f, typename UnaryFunction::argument_type a, - typename UnaryFunction::argument_type b, int n) -{ - typename UnaryFunction::result_type tmp1 = 0; - for(int i = 1; i <= n-1; ++i) - tmp1 += f(a+(b-a)/n*i); - typename UnaryFunction::result_type tmp2 = 0; - for(int i = 1; i <= n ; ++i) - tmp2 += f(a+(b-a)/2/n*(2*i-1)); - - return (b-a)/6/n * (f(a) + f(b) + 2*tmp1 + 4*tmp2); -} - -// compute b so that f(b) = y; assume f is monotone increasing -template -inline typename UnaryFunction::argument_type -invert_monotone_inc(UnaryFunction f, typename UnaryFunction::result_type y, - typename UnaryFunction::argument_type lower = -1, - typename UnaryFunction::argument_type upper = 1) -{ - while(upper-lower > 1e-6) { - double middle = (upper+lower)/2; - if(f(middle) > y) - upper = middle; - else - lower = middle; - } - return (upper+lower)/2; -} - -// compute b so that I(f(x), a, b) == y -template -inline typename UnaryFunction::argument_type -quantil(UnaryFunction f, typename UnaryFunction::argument_type a, - typename UnaryFunction::result_type y, - typename UnaryFunction::argument_type step) -{ - typedef typename UnaryFunction::result_type result_type; - if(y >= 1.0) - return std::numeric_limits::infinity(); - typename UnaryFunction::argument_type b = a; - for(result_type result = 0; result < y; b += step) - result += step*f(b); - return b; -} - - -#endif /* INTEGRATE_HPP */ diff --git a/nondet_random.html b/nondet_random.html deleted file mode 100644 index 4ef8667..0000000 --- a/nondet_random.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - -Boost RNG Library - Non-Deterministic Random Number Generators - - - - -

c++boost.gif (8819 bytes)Header -<boost/nondet_random.hpp>

- - - -

Header<boost/nondet_random.hpp> -Synopsis

- -
-namespace boost {
-  class random_device;
-} // namespace boost
-
- - -

Class random_device

- -

Synopsis

- -
-class random_device : noncopyable
-{
-public:
-  typedef unsigned int result_type;
-  static const bool has_fixed_range = true;
-  static const result_type min_value = /* implementation defined */;
-  static const result_type max_value = /* implementation defined */;
-  result_type min() const;
-  result_type max() const;
-  explicit random_device(const std::string& token = default_token);
-  ~random_device();
-  double entropy() const;
-  unsigned int operator()();
-};
-
- -

Description

- -Class random_device models a -non-deterministic random number -generator. -It uses one or more implementation-defined stochastic processes to -generate a sequence of uniformly distributed non-deterministic random -numbers. For those environments where a non-deterministic random -number generator is not available, class random_device -must not be implemented. See -
-"Randomness Recommendations for Security", D. Eastlake, S. -Crocker, J. Schiller, Network Working Group, RFC 1750, December 1994 -
-for further discussions. - -

-Note: Some operating systems abstract the computer hardware -enough to make it difficult to non-intrusively monitor stochastic -processes. However, several do provide a special device for exactly -this purpose. It seems to be impossible to emulate the functionality -using Standard C++ only, so users should be aware that this class may -not be available on all platforms. - -

Members

- -
explicit random_device(const std::string& token = default_token)
- -Effects: Constructs a random_device, -optionally using the given token as an access -specification (for example, a URL) to some implementation-defined -service for monitoring a stochastic process. - -
    double entropy() const
-Returns: An entropy estimate for the random numbers -returned by operator(), in the range min() to -log2( max()+1). A deterministic random -number generator (e.g. a pseudo-random number engine) has entropy 0. -
-Throws: Nothing. - - -

Implementation Note for Linux

- -On the Linux operating system, token is interpreted as a -filesystem path. It is assumed that this path denotes an operating -system pseudo-device which generates a stream of non-deterministic -random numbers. The pseudo-device should never signal an error or -end-of-file. Otherwise, std::ios_base::failure is -thrown. By default, random_device uses the -/dev/urandom pseudo-device to retrieve the random -numbers. Another option would be to specify the -/dev/random pseudo-device, which blocks on reads if the -entropy pool has no more random bits available. - - -

Performance

- -The test program nondet_random_speed.cpp -measures the execution times of the -nondet_random.hpp implementation of the above -algorithms in a tight loop. The performance has been evaluated on a -Pentium Pro 200 MHz with gcc 2.95.2, Linux 2.2.13, glibc 2.1.2. - -

- - - -
classtime per invocation [usec]
random_device92.0
- -

-The measurement error is estimated at +/- 1 usec. - -

-


-Jens Maurer, 2000-06-19 - - - - \ No newline at end of file diff --git a/nondet_random_speed.cpp b/nondet_random_speed.cpp deleted file mode 100644 index 2944401..0000000 --- a/nondet_random_speed.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* boost nondet_random_speed.cpp performance test - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - */ - -#include -#include -#include -#include - -// set to your CPU frequency in MHz -static const double cpu_frequency = 200 * 1e6; - -static void show_elapsed(double end, int iter, const std::string & name) -{ - double usec = end/iter*1e6; - double cycles = usec * cpu_frequency/1e6; - std::cout << name << ": " - << usec*1e3 << " nsec/loop = " - << cycles << " CPU cycles" - << std::endl; -} - -template -static void timing(RNG & rng, int iter, const std::string& name) -{ - volatile Result tmp; // make sure we're not optimizing too much - boost::timer t; - for(int i = 0; i < iter; i++) - tmp = rng(); - show_elapsed(t.elapsed(), iter, name); -} - -template -void run(int iter, const std::string & name) -{ - RNG rng; - timing(rng, iter, name); -} - -int main(int argc, char*argv[]) -{ - if(argc != 2) { - std::cerr << "usage: " << argv[0] << " iterations" << std::endl; - return 1; - } - - int iter = std::atoi(argv[1]); - -#ifdef __linux__ - boost::random_device dev; - timing(dev, iter, "random_device"); -#else -#error The non-deterministic random device is currently available on Linux only. -#endif - - return 0; -} diff --git a/random-concepts.html b/random-concepts.html deleted file mode 100644 index cf171fe..0000000 --- a/random-concepts.html +++ /dev/null @@ -1,429 +0,0 @@ - - - - - -Boost Random Number Library Concepts - - - - -

Random Number Generator Library Concepts

- - -

Introduction

- -Random numbers are required in a number of different problem domains, -such as -
    -
  • numerics (simulation, Monte-Carlo integration) -
  • games (non-deterministic enemy behavior) -
  • security (key generation) -
  • testing (random coverage in white-box tests) -
- -The Boost Random Number Generator Library provides a framework -for random number generators with well-defined properties so that the -generators can be used in the demanding numerics and security domains. - -For a general introduction to random numbers in numerics, see -
-"Numerical Recipes in C: The art of scientific computing", William -H. Press, Saul A. Teukolsky, William A. Vetterling, Brian P. Flannery, -2nd ed., 1992, pp. 274-328 -
- -Depending on the requirements of the problem domain, different -variations of random number generators are appropriate: - -
    -
  • non-deterministic random number generator -
  • pseudo-random number generator -
  • quasi-random number generator -
- -All variations have some properties in common, these concepts (in the -STL sense) are called NumberGenerator and -UniformRandomNumberGenerator. Each concept will be defined in a -subsequent section. - -

- -The goals for this library are the following: -

    -
  • allow easy integration of third-party random-number generators -
  • define a validation interface for the generators -
  • provide easy-to-use front-end classes which model popular -distributions -
  • provide maximum efficiency -
  • allow control on quantization effects in front-end processing -(not yet done) -
- - -

Number Generator

- -A number generator is a function object (std:20.3 -[lib.function.objects]) that takes zero arguments. Each call to -operator() returns a number. - - -In the following table, X denotes a number generator -class returning objects of type T, and u is -a value of X. - -

- - - - - - - - -
NumberGenerator -requirements
expressionreturn typepre/post-condition
X::result_typeTstd::numeric_limits<T>::is_specialized is true, -T is LessThanComparable
u.operator()()T-
- -

- -Note: The NumberGenerator requirements do not impose any -restrictions on the characteristics of the returned numbers. - - -

Uniform Random Number Generator

- -A uniform random number generator is a NumberGenerator that provides a -sequence of random numbers uniformly distributed on a given range. -The range can be compile-time fixed or available (only) after run-time -construction of the object. - -

-The tight lower bound of some (finite) set S is the (unique) -member l in S, so that for all v in S, l <= v holds. Likewise, the -tight upper bound of some (finite) set S is the (unique) -member u in S, so that for all v in S, v <= u holds. - -

-In the following table, X denotes a number generator -class returning objects of type T, and v is -a const value of X. - -

- - - - - - - - - - - - - - - -
UniformRandomNumberGenerator -requirements
expressionreturn typepre/post-condition
X::has_fixed_rangeboolcompile-time constant; if true, the range on which -the random numbers are uniformly distributed is known at compile-time -and members min_value and max_value -exist. Note: This flag may also be false due to -compiler limitations.
X::min_valueTcompile-time constant; min_value is equal to -v.min()
X::max_valueTcompile-time constant; max_value is equal to -v.max()
v.min()Ttight lower bound on the set of all values returned by -operator(). The return value of this function shall not -change during the lifetime of the object.
v.max()Tif std::numeric_limits<T>::is_integer, tight -upper bound on the set of all values returned by -operator(), otherwise, the smallest representable number -larger than the tight upper bound on the set of all values returned by -operator(). In any case, the return value of this -function shall not change during the lifetime of the -object.
- -

-The member functions min, max, and -operator() shall have amortized constant time complexity. - -

-Note: For integer generators (i.e. integer T), -the generated values x fulfill min() <= x <= -max(), for non-integer generators (i.e. non-integer -T), the generated values x fulfill -min() <= x < max(). -
-Rationale: The range description with min and -max serves two purposes. First, it allows scaling of the -values to some canonical range, such as [0..1). Second, it describes -the significant bits of the values, which may be relevant for further -processing. -
-The range is a closed interval [min,max] for integers, because the -underlying type may not be able to represent the half-open interval -[min,max+1). It is a half-open interval [min, max) for non-integers, -because this is much more practical for borderline cases of continuous -distributions. -

- -Note: The UniformRandomNumberGenerator concept does not -require operator()(long) and thus it does not fulfill the -RandomNumberGenerator (std:25.2.11 [lib.alg.random.shuffle]) -requirements. Use the -random_number_generator -adapter for that. -
- -Rationale: operator()(long) is not provided, -because mapping the output of some generator with integer range to a -different integer range is not trivial. - - -

Non-deterministic Uniform Random Number -Generator

- -A non-deterministic uniform random number generator is a -UniformRandomNumberGenerator that is based on some stochastic process. -Thus, it provides a sequence of truly-random numbers. Examples for -such processes are nuclear decay, noise of a Zehner diode, tunneling -of quantum particles, rolling a die, drawing from an urn, and tossing -a coin. Depending on the environment, inter-arrival times of network -packets or keyboard events may be close approximations of stochastic -processes. -

- -The class -random_device -is a model for a non-deterministic random number generator. - -

- -Note: This type of random-number generator is useful for -security applications, where it is important to prevent that an -outside attacker guesses the numbers and thus obtains your -encryption or authentication key. Thus, models of this concept should -be cautious not to leak any information, to the extent possible by the -environment. For example, it might be advisable to explicitly clear -any temporary storage as soon as it is no longer needed. - - -

Pseudo-Random Number Generator

- -A pseudo-random number generator is a UniformRandomNumberGenerator -which provides a deterministic sequence of pseudo-random numbers, -based on some algorithm and internal state. Linear congruential and -inversive congruential generators are examples of such pseudo-random -number generators. Often, these generators are very sensitive to -their parameters. In order to prevent wrong implementations from -being used, an external testsuite should check that the generated -sequence and the validation value provided do indeed match. -

- -Donald E. Knuth gives an extensive overview on pseudo-random number -generation in his book "The Art of Computer Programming, Vol. 2, 3rd -edition, Addison-Wesley, 1997". The descriptions for the specific -generators contain additional references. -

- -Note: Because the state of a pseudo-random number generator -is necessarily finite, the sequence of numbers returned by the -generator will loop eventually. - -

-In addition to the UniformRandomNumberGenerator requirements, a -pseudo-random number generator has some additional requirements. In -the following table, X denotes a pseudo-random number -generator class returning objects of type T, -x is a value of T, u is a value -of X, and v is a const value of -X. - -

- - - - - - - - - - - -
PseudoRandomNumberGenerator -requirements
expressionreturn typepre/post-condition
X()-creates a generator in some implementation-defined -state. Note: Several generators thusly created may possibly -produce dependent or identical sequences of random numbers.
explicit X(...)-creates a generator with user-provided state; the implementation -shall specify the constructor argument(s)
u.seed(...)voidsets the current state according to the argument(s); at least -functions with the same signature as the non-default -constructor(s) shall be provided. -
X::validation(x)boolcompares the pre-computed and hardcoded 10001th element in the -generator's random number sequence with x. The generator -must have been constructed by its default constructor and -seed must not have been called for the validation to -be meaningful. -
- -

- -Note: The seed member function is similar to the -assign member function in STL containers. However, the -naming did not seem appropriate. - -

- -Classes which model a pseudo-random number generator shall also model -EqualityComparable, i.e. implement operator==. Two -pseudo-random number generators are defined to be equivalent -if they both return an identical sequence of numbers starting from a -given state. -

-Classes which model a pseudo-random number generator should also model -the Streamable concept, i.e. implement operator<< -and operator>>. If so, -operator<< writes all current state of the -pseudo-random number generator to the given ostream so -that operator>> can restore the state at a later -time. The state shall be written in a platform-independent manner, -but it is assumed that the locales used for writing and -reading be the same. - -The pseudo-random number generator with the restored state and the -original at the just-written state shall be equivalent. -

- -Classes which model a pseudo-random number generator may also model -the CopyConstructible and Assignable concepts. However, note that the -sequences of the original and the copy are strongly correlated (in -fact, they are identical), which may make them unsuitable for some -problem domains. Thus, copying pseudo-random number generators is -discouraged; they should always be passed by (non-const) -reference. - -

- -The classes -rand48, -minstd_rand, -and -mt19937 -are models for a pseudo-random number generator. - -

-Note: This type of random-number generator is useful for -numerics, games and testing. The non-zero arguments constructor(s) -and the seed() member function(s) allow for a -user-provided state to be installed in the generator. This is useful -for debugging Monte-Carlo algorithms and analyzing particular test -scenarios. The Streamable concept allows to save/restore the state of -the generator, for example to re-run a test suite at a later time. - -

Random Distribution

- -A radom distribution produces random numbers distributed according to -some distribution, given uniformly distributed random values as input. - -In the following table, X denotes a random distribution -class returning objects of type T, u is a -value of X, x is a (possibly const) -value of X, and e is an lvalue of an -arbitrary type that meets the requirements of a uniform random number -generator, returning values of type U. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Random distribution requirements -(in addition to number generator, -CopyConstructible, and Assignable)
expressionreturn typepre/post-conditioncomplexity
X::input_typeU-compile-time
u.reset()voidsubsequent uses of u do not depend on values -produced by e prior to invoking reset.constant
u(e)Tthe sequence of numbers returned by successive invocations with -the same object e is randomly distributed with some -probability density function p(x)amortized constant number of invocations of e
os << xstd::ostream&writes a textual representation for the parameters and additional -internal data of the distribution x to os. -
-post: The os.fmtflags and fill character are -unchanged.
O(size of state)
is >> ustd::istream&restores the parameters and additional internal data of the -distribution u. -
-pre: is provides a textual representation that was -previously written by operator<< -
-post: The is.fmtflags are unchanged.
O(size of state)
-

- -Additional requirements: The sequence of numbers produced by -repeated invocations of x(e) does not change whether or -not os << x is invoked between any of the -invocations x(e). If a textual representation -is written using os << x and that representation -is restored into the same or a different object y of the -same type using is >> y, repeated invocations of -y(e) produce the same sequence of random numbers as would -repeated invocations of x(e). -

- -

Quasi-Random Number Generators

- -A quasi-random number generator is a Number Generator which provides a -deterministic sequence of numbers, based on some algorithm and -internal state. The numbers do not have any statistical properties -(such as uniform distribution or independence of successive values). - -

- -Note: Quasi-random number generators are useful for -Monte-Carlo integrations where specially crafted sequences of random -numbers will make the approximation converge faster. - -

- -[Does anyone have a model?] - -

-


-Jens Maurer, 2000-02-23 - - - diff --git a/random-distributions.html b/random-distributions.html deleted file mode 100644 index a77a421..0000000 --- a/random-distributions.html +++ /dev/null @@ -1,796 +0,0 @@ - - - - - - -Boost Random Number Library Distributions - - - - -

Random Number Library Distributions

- - - -

Introduction

- -In addition to the random number -generators, this library provides distribution functions which map -one distribution (often a uniform distribution provided by some -generator) to another. - -

-Usually, there are several possible implementations of any given -mapping. Often, there is a choice between using more space, more -invocations of the underlying source of random numbers, or more -time-consuming arithmetic such as trigonometric functions. This -interface description does not mandate any specific implementation. -However, implementations which cannot reach certain values of the -specified distribution or otherwise do not converge statistically to -it are not acceptable. - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
distributionexplanationexample
uniform_smallintdiscrete uniform distribution on a small set of integers (much -smaller than the range of the underlying generator)drawing from an urn
uniform_intdiscrete uniform distribution on a set of integers; the underlying -generator may be called several times to gather enough randomness for -the outputdrawing from an urn
uniform_01continuous uniform distribution on the range [0,1); important -basis for other distributions-
uniform_realcontinuous uniform distribution on some range [min, max) of real -numbersfor the range [0, 2pi): randomly dropping a stick and measuring -its angle in radiants (assuming the angle is uniformly -distributed)
bernoulli_distributionBernoulli experiment: discrete boolean valued distribution with -configurable probabilitytossing a coin (p=0.5)
geometric_distributionmeasures distance between outcomes of repeated Bernoulli experimentsthrowing a die several times and counting the number of tries -until a "6" appears for the first time
triangle_distribution??
exponential_distributionexponential distributionmeasuring the inter-arrival time of alpha particles emitted by -radioactive matter
normal_distributioncounts outcomes of (infinitely) repeated Bernoulli experimentstossing a coin 10000 times and counting how many front sides are shown
lognormal_distributionlognormal distribution (sometimes used in simulations)measuring the job completion time of an assembly line worker
uniform_on_sphereuniform distribution on a unit sphere of arbitrary dimensionchoosing a random point on Earth (assumed to be a sphere) where to -spend the next vacations
- -

- -The template parameters of the distribution functions are always in -the order -

    -
  • Underlying source of random numbers -
  • If applicable, return type, with a default to a reasonable type. -
- -

-The distribution functions no longer satisfy the input iterator -requirements (std:24.1.1 [lib.input.iterators]), because this is -redundant given the Generator interface and imposes a run-time -overhead on all users. Moreover, a Generator interface appeals to -random number generation as being more "natural". Use an -iterator adaptor -if you need to wrap any of the generators in an input iterator -interface. -

- -All of the distribution functions described below store a non-const -reference to the underlying source of random numbers. Therefore, the -distribution functions are not Assignable. However, they are -CopyConstructible. Copying a distribution function will copy the -parameter values. Furthermore, both the copy and the original will -refer to the same underlying source of random numbers. Therefore, -both the copy and the original will obtain their underlying random -numbers from a single sequence. - -

-In this description, I have refrained from documenting those members -in detail which are already defined in the -concept documentation. - - -

Synopsis of the distributions available from header -<boost/random.hpp>

- -
-namespace boost {
-  template<class IntType = int>
-  class uniform_smallint;
-  template<class IntType = int>
-  class uniform_int;
-  template<class RealType = double>
-  class uniform_01;
-  template<class RealType = double>
-  class uniform_real;
-
-  // discrete distributions
-  template<class RealType = double>
-  class bernoulli_distribution;
-  template<class IntType = int>
-  class geometric_distribution;
-
-  // continuous distributions
-  template<class RealType = double>
-  class triangle_distribution;
-  template<class RealType = double>
-  class exponential_distribution;
-  template<class RealType = double>
-  class normal_distribution;
-  template<class RealType = double>
-  class lognormal_distribution;
-  template<class RealType = double,
-    class Cont = std::vector<RealType> >
-  class uniform_on_sphere;
-}
-
- -

Class template -uniform_smallint

- -

Synopsis

- -
-#include <boost/random/uniform_smallint.hpp>
-
-template<class IntType = int>
-class uniform_smallint
-{
-public:
-  typedef IntType input_type;
-  typedef IntType result_type;
-  static const bool has_fixed_range = false;
-  uniform_smallint(IntType min, IntType max);
-  result_type min() const;
-  result_type max() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -The distribution function uniform_smallint models a -random distribution. -On each invocation, it returns a random integer value -uniformly distributed in the set of integer numbers {min, min+1, -min+2, ..., max}. It assumes that the desired range (max-min+1) is -small compared to the range of the underlying source of random -numbers and thus makes no attempt to limit quantization errors. -

-Let rout=(max-min+1) the desired range of integer numbers, -and let rbase be the range of the underlying source of -random numbers. Then, for the uniform distribution, the theoretical -probability for any number i in the range rout will be -pout(i) = 1/rout. Likewise, assume a uniform -distribution on rbase for the underlying source of random -numbers, i.e. pbase(i) = 1/rbase. Let -pout_s(i) denote the random distribution generated by -uniform_smallint. Then the sum over all i in -rout of (pout_s(i)/pout(i) --1)2 shall not exceed -rout/rbase2 (rbase mod -rout)(rout - rbase mod -rout). -

- -The template parameter IntType shall denote an -integer-like value type. - -

-Note: The property above is the square sum of the relative -differences in probabilities between the desired uniform distribution -pout(i) and the generated distribution -pout_s(i). The property can be fulfilled with the -calculation (base_rng mod rout), as follows: Let r = -rbase mod rout. The base distribution on -rbase is folded onto the range rout. The -numbers i < r have assigned (rbase div -rout)+1 numbers of the base distribution, the rest has only -(rbase div rout). Therefore, -pout_s(i) = ((rbase div rout)+1) / -rbase for i < r and pout_s(i) = -(rbase div rout)/rbase otherwise. -Substituting this in the above sum formula leads to the desired -result. -

-Note: The upper bound for (rbase mod rout)(rout - rbase -mod rout) is rout2/4. Regarding the upper bound for the square -sum of the relative quantization error of rout3/(4*rbase2), it -seems wise to either choose rbase so that rbase > 10*rout2 or -ensure that rbase is divisible by rout. - - -

Members

- -
uniform_smallint(IntType min, IntType max)
- -Effects: Constructs a uniform_smallint -functor. min and max are the lower and upper -bounds of the output range, respectively. - - -

Class template uniform_int

- -

Synopsis

- -
-#include <boost/random/uniform_int.hpp>
-
-template<class IntType = int>
-class uniform_int
-{
-public:
-  typedef IntType input_type;
-  typedef IntType result_type;
-  static const bool has_fixed_range = false;
-  explicit uniform_int(IntType min = 0, IntType max = 9);
-  result_type min() const;
-  result_type max() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng, result_type n);
-};
-
- -

Description

- -The distribution function uniform_int models a -random distribution. -On each invocation, it returns a random integer -value uniformly distributed in the set of integer numbers -{min, min+1, min+2, ..., max}. -

- -The template parameter IntType shall denote an -integer-like value type. - -

Members

- -
    uniform_int(IntType min = 0, IntType max = 9)
-Requires: min <= max -
-Effects: Constructs a uniform_int -object. min and max are the parameters of -the distribution. - -
    result_type min() const
-Returns: The "min" parameter of the distribution. - -
    result_type max() const
-Returns: The "max" parameter of the distribution. - -
    result_type operator()(UniformRandomNumberGenerator& urng, result_type 
-n)
-Returns: A uniform random number x in the range 0 -<= x < n. [Note: This allows a -variate_generator object with a uniform_int -distribution to be used with std::random_shuffe, see -[lib.alg.random.shuffle]. ] - - -

Class template uniform_01

- -

Synopsis

- -
-#include <boost/random/uniform_01.hpp>
-
-template<class UniformRandomNumberGenerator, class RealType = double>
-class uniform_01
-{
-public:
-  typedef UniformRandomNumberGenerator base_type;
-  typedef RealType result_type;
-  static const bool has_fixed_range = false;
-  explicit uniform_01(base_type & rng);
-  result_type operator()();
-  result_type min() const;
-  result_type max() const;
-};
-
- -

Description

- -The distribution function uniform_01 models a -random distribution. -On each invocation, it returns a random floating-point value uniformly -distributed in the range [0..1). - -The value is computed using -std::numeric_limits<RealType>::digits random binary -digits, i.e. the mantissa of the floating-point value is completely -filled with random bits. [Note: Should this be configurable?] - -

-The template parameter RealType shall denote a float-like -value type with support for binary operators +, -, and /. It must be -large enough to hold floating-point numbers of value -rng.max()-rng.min()+1. -

-base_type::result_type must be a number-like value type, -it must support static_cast<> to -RealType and binary operator -. - -

- -Note: The current implementation is buggy, because it may not -fill all of the mantissa with random bits. I'm unsure how to fill a -(to-be-invented) boost::bigfloat class with random bits -efficiently. It's probably time for a traits class. - -

Members

- -
explicit uniform_01(base_type & rng)
- -Effects: Constructs a uniform_01 functor -with the given uniform random number generator as the underlying -source of random numbers. - - -

Class template uniform_real

- -

Synopsis

- -
-#include <boost/random/uniform_real.hpp>
-
-template<class RealType = double>
-class uniform_real
-{
-public:
-  typedef RealType input_type;
-  typedef RealType result_type;
-  static const bool has_fixed_range = false;
-  uniform_real(RealType min = RealType(0), RealType max = RealType(1));
-  result_type min() const;
-  result_type max() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -The distribution function uniform_real models a -random distribution. -On each invocation, it returns a random floating-point -value uniformly distributed in the range [min..max). The value is -computed using -std::numeric_limits<RealType>::digits random binary -digits, i.e. the mantissa of the floating-point value is completely -filled with random bits. -

- -Note: The current implementation is buggy, because it may not -fill all of the mantissa with random bits. - - -

Members

- -
    uniform_real(RealType min = RealType(0), RealType max = RealType(1))
-Requires: min <= max -
-Effects: Constructs a -uniform_real object; min and -max are the parameters of the distribution. - -
    result_type min() const
-Returns: The "min" parameter of the distribution. - -
    result_type max() const
-Returns: The "max" parameter of the distribution. - - -

Class template -bernoulli_distribution

- -

Synopsis

- -
-#include <boost/random/bernoulli_distribution.hpp>
-
-template<class RealType = double>
-class bernoulli_distribution
-{
-public:
-  typedef int input_type;
-  typedef bool result_type;
-
-  explicit bernoulli_distribution(const RealType& p = RealType(0.5));
-  RealType p() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -Instantiations of class template bernoulli_distribution -model a random -distribution. Such a random distribution produces -bool values distributed with probabilities P(true) = p -and P(false) = 1-p. p is the parameter of the distribution. - -

Members

- -
    bernoulli_distribution(const RealType& p = RealType(0.5))
- -Requires: 0 <= p <= 1 -
-Effects: Constructs a -bernoulli_distribution object. p is the -parameter of the distribution. - -
    RealType p() const
-Returns: The "p" parameter of the distribution. - - -

Class template -geometric_distribution

- -

Synopsis

-
-#include <boost/random/geometric_distribution.hpp>
-
-template<class UniformRandomNumberGenerator, class IntType = int>
-class geometric_distribution
-{
-public:
-  typedef RealType input_type;
-  typedef IntType result_type;
-
-  explicit geometric_distribution(const RealType& p = RealType(0.5));
-  RealType p() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- - -

Description

- -Instantiations of class template geometric_distribution -model a -random distribution. -A geometric_distribution random distribution produces -integer values i >= 1 with p(i) = (1-p) * pi-1. -p is the parameter of the distribution. - - -

Members

- -
    geometric_distribution(const RealType& p = RealType(0.5))
- -Requires: 0 < p < 1 -
-Effects: Constructs a -geometric_distribution object; p is the -parameter of the distribution. - -
   RealType p() const
-Returns: The "p" parameter of the distribution. - - -

Class template -triangle_distribution

- -

Synopsis

-
-#include <boost/random/triangle_distribution.hpp>
-
-template<class RealType = double>
-class triangle_distribution
-{
-public:
-  typedef RealType input_type;
-  typedef RealType result_type;
-  triangle_distribution(result_type a, result_type b, result_type c);
-  result_type a() const;
-  result_type b() const;
-  result_type c() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -Instantiations of class template triangle_distribution -model a random -distribution. The returned floating-point values x -satisfy a <= x <= c; x has a triangle -distribution, where b is the most probable value for -x. - -

Members

- -
triangle_distribution(result_type a, result_type b, result_type c)
- -Effects: Constructs a -triangle_distribution functor. a, b, c are -the parameters for the distribution. -

- - -

Class template -exponential_distribution

- -

Synopsis

-
-#include <boost/random/exponential_distribution.hpp>
-
-template<class RealType = double>
-class exponential_distribution
-{
-public:
-  typedef RealType input_type;
-  typedef RealType result_type;
-  explicit exponential_distribution(const result_type& lambda);
-  RealType lambda() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -Instantiations of class template exponential_distribution -model a random -distribution. Such a distribution produces random numbers x > -0 distributed with probability density function p(x) = lambda * -exp(-lambda * x), where lambda is the parameter of the distribution. - -

Members

- -
    exponential_distribution(const result_type& lambda = result_type(1))
-Requires: lambda > 0 -
-Effects: Constructs an -exponential_distribution object with rng as -the reference to the underlying source of random -numbers. lambda is the parameter for the distribution. - -
    RealType lambda() const
-Returns: The "lambda" parameter of the distribution. - - -

Class template -normal_distribution

- -

Synopsis

- -
-#include <boost/random/normal_distribution.hpp>
-
-template<class RealType = double>
-class normal_distribution
-{
-public:
-  typedef RealType input_type;
-  typedef RealType result_type;
-  explicit normal_distribution(const result_type& mean = 0,
-			       const result_type& sigma = 1);
-  RealType mean() const;
-  RealType sigma() const;
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -Instantiations of class template normal_distribution -model a random -distribution. Such a distribution produces random numbers x -distributed with probability density function p(x) = -1/sqrt(2*pi*sigma) * exp(- (x-mean)2 / -(2*sigma2) ), where mean and sigma are the parameters of -the distribution. - - -

Members

- -
-    explicit normal_distribution(const result_type& mean = 0,
-                                 const result_type& sigma = 1);
-
- -Requires: sigma > 0 -
-Effects: Constructs a -normal_distribution object; mean and -sigma are the parameters for the distribution. - -
    RealType mean() const
-Returns: The "mean" parameter of the distribution. - -
    RealType sigma() const
-Returns: The "sigma" parameter of the distribution. - - -

Class template -lognormal_distribution

- -

Synopsis

- -
-#include <boost/random/lognormal_distribution.hpp>
-
-template<class RealType = double>
-class lognormal_distribution
-{
-public:
-  typedef typename normal_distribution<RealType>::input_type
-  typedef RealType result_type;
-  explicit lognormal_distribution(const result_type& mean = 1.0,
-			          const result_type& sigma = 1.0);
-  RealType& mean() const;
-  RealType& sigma() const;                                 
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  result_type operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -Instantiations of class template lognormal_distribution -model a random -distribution. Such a distribution produces random numbers -with p(x) = 1/(x * normal_sigma * sqrt(2*pi)) * exp( --(log(x)-normal_mean)2 / (2*normal_sigma2) ) -for x > 0, -where normal_mean = log(mean2/sqrt(sigma2 -+ mean2)) -and normal_sigma = sqrt(log(1 + sigma2/mean2)). - - -

Members

- -
lognormal_distribution(const result_type& mean,
-	   	       const result_type& sigma)
- -Effects: Constructs a -lognormal_distribution functor. mean and -sigma are the mean and standard deviation of the -lognormal distribution. -

- - -

Class template -uniform_on_sphere

- -

Synopsis

- -
-#include <boost/random/uniform_on_sphere.hpp>
-
-template<class RealType = double,
-  class Cont = std::vector<RealType> >
-class uniform_on_sphere
-{
-public:
-  typedef RealType input_type;
-  typedef Cont result_type;
-  explicit uniform_on_sphere(int dim = 2);
-  void reset();
-  template<class UniformRandomNumberGenerator>
-  const result_type & operator()(UniformRandomNumberGenerator& urng);
-};
-
- -

Description

- -Instantiations of class template uniform_on_sphere model a -random distribution. -Such a distribution produces random numbers uniformly distributed on -the unit sphere of arbitrary dimension dim. The -Cont template parameter must be a STL-like container type -with begin and end operations returning -non-const ForwardIterators of type Cont::iterator. - -

Members

- -
explicit uniform_on_sphere(int dim = 2)
- -Effects: Constructs a uniform_on_sphere -functor. dim is the dimension of the sphere. -

- -

-


-Jens Maurer, 2003-10-25 - - - diff --git a/random-generators.html b/random-generators.html deleted file mode 100644 index e06c65b..0000000 --- a/random-generators.html +++ /dev/null @@ -1,1038 +0,0 @@ - - - - - - -Boost Random Number Library Generators - - - - -

Random Number Library Generators

- - - -

Introduction

- -This library provides several pseudo-random number generators. The -quality of a pseudo-random number generator crucially depends on both -the algorithm and its parameters. This library implements the -algorithms as class templates with template value parameters, hidden -in namespace boost::random. Any particular choice of -parameters is represented as the appropriately specializing -typedef in namespace boost. -

- -Pseudo-random number generators should not be constructed -(initialized) frequently during program execution, for two reasons. -First, initialization requires full initialization of the internal -state of the generator. Thus, generators with a lot of internal state -(see below) are costly to initialize. Second, initialization always -requires some value used as a "seed" for the generated sequence. It -is usually difficult to obtain several good seed values. For example, -one method to obtain a seed is to determine the current time at the -highest resolution available, e.g. microseconds or nanoseconds. When -the pseudo-random number generator is initialized again with the -then-current time as the seed, it is likely that this is at a -near-constant (non-random) distance from the time given as the seed -for first initialization. The distance could even be zero if the -resolution of the clock is low, thus the generator re-iterates the -same sequence of random numbers. For some applications, this is -inappropriate. -

- -Note that all pseudo-random number generators described below are -CopyConstructible and Assignable. Copying or assigning a generator -will copy all its internal state, so the original and the copy will -generate the identical sequence of random numbers. Often, such -behavior is not wanted. In particular, beware of the algorithms from -the standard library such as std::generate. They take a functor -argument by value, thereby invoking the copy constructor when called. -

- -The following table gives an overview of some characteristics of the -generators. The cycle length is a rough estimate of the quality of -the generator; the approximate relative speed is a performance -measure, higher numbers mean faster random number generation. - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
generatorlength of cycleapprox. memory requirementsapprox. relative speedcomment
minstd_rand231-2sizeof(int32_t)40-
rand48248-1sizeof(uint64_t)80-
lrand48 (C library)248-1-20global state
ecuyer1988approx. 2612*sizeof(int32_t)20-
kreutzer1986?1368*sizeof(uint32_t)60-
hellekalek1995231-1sizeof(int32_t)3good uniform distribution in several dimensions
mt11213b211213-1352*sizeof(uint32_t)100good uniform distribution in up to 350 dimensions
mt19937219937-1625*sizeof(uint32_t)100good uniform distribution in up to 623 dimensions
lagged_fibonacci607approx. 232000607*sizeof(double)150-
lagged_fibonacci1279approx. 2670001279*sizeof(double)150-
lagged_fibonacci2281approx. 21200002281*sizeof(double)150-
lagged_fibonacci3217approx. 21700003217*sizeof(double)150-
lagged_fibonacci4423approx. 22300004423*sizeof(double)150-
lagged_fibonacci9689approx. 25100009689*sizeof(double)150-
lagged_fibonacci19937approx. 2105000019937*sizeof(double)150-
lagged_fibonacci23209approx. 2120000023209*sizeof(double)140-
lagged_fibonacci44497approx. 2230000044497*sizeof(double)60-
- -

-As observable from the table, there is generally a -quality/performance/memory trade-off to be decided upon when choosing -a random-number generator. The multitude of generators provided in -this library allows the application programmer to optimize the -trade-off with regard to his application domain. Additionally, -employing several fundamentally different random number generators for -a given application of Monte Carlo simulation will improve the -confidence in the results. -

- -If the names of the generators don't ring any bell and you have no -idea which generator to use, it is reasonable to employ -mt19937 for a start: It is fast and has acceptable -quality. - -

-Note: These random number generators are not intended for use -in applications where non-deterministic random numbers are required. -See nondet_random.html for a choice -of (hopefully) non-deterministic random number generators. - -

-In this description, I have refrained from documenting those members -in detail which are already defined in the -concept documentation. - - -

Synopsis of the generators available from header -<boost/random.hpp>

- -
-namespace boost {
-  namespace random {
-    template<class IntType, IntType m>
-    class const_mod;
-    template<class IntType, IntType a, IntType c, IntType m, IntType val>
-    class linear_congruential;
-  }
-  class rand48;
-  typedef random::linear_congruential< /* ... */ > minstd_rand0;
-  typedef random::linear_congruential< /* ... */ > minstd_rand;
-
-  namespace random {
-    template<class DataType, int w, int n, int m, int r, DataType a, int u,
-        int s, DataType b, int t, DataType c, int l, IntType val>
-    class mersenne_twister;
-  }
-  typedef random::mersenne_twister< /* ... */ > mt11213b;
-  typedef random::mersenne_twister< /* ... */ > mt19937;
-
-  namespace random {
-    template<class FloatType, unsigned int  p, unsigned int q>
-    class lagged_fibonacci;
-  }
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci607;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci1279;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci2281;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci3217;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci4423;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci9689;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci19937;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci23209;
-  typedef random::lagged_fibonacci< /* ... */ > lagged_fibonacci44497;  
-} // namespace boost
-
- - -

Class template -random::const_mod

- -

Synopsis

- -
-template<class IntType, IntType m>
-class random::const_mod
-{
-public:
-  template<IntType c>
-  static IntType add(IntType x);
-
-  template<IntType a>
-  static IntType mult(IntType x);
-
-  template<IntType a, IntType c>
-  static IntType mult_add(IntType x);
-
-  static IntType invert(IntType x);
-private:
-  const_mod();         // don't instantiate
-};
-
- -

Description

- -Class template const_mod provides functions performing -modular arithmetic, carefully avoiding overflows. All member -functions are static; there shall be no objects of type -const_mod<>. -

- -The template parameter IntType shall denote an integral -type, m is the modulus. -

- -Note: For modulo multiplications with large m, a trick allows -fast computation under certain conditions, see -

-"A more portable FORTRAN random number generator", Linus Schrage, ACM -Transactions on Mathematical Software, Vol. 5, No. 2, June 1979, pp. 132-138 -
- - -

Member functions

- -
template<IntType c> static IntType add(IntType x)
- -Returns: (x+c) mod m - -
template<IntType a> static IntType mult(IntType x)
- -Returns: (a*x) mod m - -
template<IntType a, IntType c> static IntType
-mult_add(IntType x)
- -Returns: (a*x+c) mod m - -
static IntType invert(IntType x)
- -Returns: i so that (a*i) mod m == 1 -
-Precondition: m is prime - - -

Class template -random::linear_congruential

- -

Synopsis

- -
-#include <boost/random/linear_congruential.hpp>
-
-template<class IntType, IntType a, IntType c, IntType m, IntType val>
-class linear_congruential
-{
-public:
-  typedef IntType result_type;
-  static const IntType multiplier = a;
-  static const IntType increment = c;
-  static const IntType modulus = m;
-  static const bool has_fixed_range = true;
-  static const result_type min_value;
-  static const result_type max_value;
-  explicit linear_congruential_fixed(IntType x0 = 1);
-  // compiler-generated copy constructor and assignment operator are fine
-  void seed(IntType x0);
-  IntType operator()();
-};
-
-typedef random::linear_congruential<long, 16807L, 0, 2147483647L,
-     1043618065L> minstd_rand0;
-typedef random::linear_congruential<long, 48271L, 0, 2147483647L,
-     399268537L> minstd_rand;
-
- -

Description

- -Instantiations of class template linear_congruential -model a pseudo-random number -generator. Linear congruential pseudo-random number generators -are described in: -
-"Mathematical methods in large-scale computing units", D. H. Lehmer, -Proc. 2nd Symposium on Large-Scale Digital Calculating Machines, -Harvard University Press, 1951, pp. 141-146 -
- -Let x(n) denote the sequence of numbers returned by -some pseudo-random number generator. Then for the linear congruential -generator, x(n+1) := (a * x(n) + c) mod m. Parameters for the -generator are x(0), a, c, m. - -The template parameter IntType shall denote an -integral type. It must be large enough to hold values a, c, and m. -The template parameters a and c must be smaller than m. - -

- -Note: The quality of the generator crucially depends on the -choice of the parameters. User code should use one of the sensibly -parameterized generators such as minstd_rand instead. -
-For each choice of the parameters a, c, m, some distinct type is -defined, so that the static members do not interfere with -regard to the one definition rule. - -

Members

- -
explicit linear_congruential(IntType x0 = 1)
- -Effects: Constructs a -linear_congruential generator with x(0) := -x0. - -
void seed(IntType x0)
- -Effects: Changes the current value x(n) of the -generator to x0. - -

Specializations

- -The specialization minstd_rand0 was originally suggested -in -
-A pseudo-random number generator for the System/360, P.A. Lewis, -A.S. Goodman, J.M. Miller, IBM Systems Journal, Vol. 8, No. 2, 1969, -pp. 136-146 -
- -It is examined more closely together with minstd_rand in -
-"Random Number Generators: Good ones are hard to find", Stephen -K. Park and Keith W. Miller, Communications of the ACM, Vol. 31, -No. 10, October 1988, pp. 1192-1201 -
- - -

Class rand48

- -

Synopsis

-
-#include <boost/random/linear_congruential.hpp>
-
-class rand48 
-{
-public:
-  typedef int32_t result_type;
-  static const bool has_fixed_range = true;
-  static const int32_t min_value = 0;
-  static const int32_t max_value = 0x7fffffff;
-  
-  explicit rand48(int32_t x0 = 1);
-  explicit rand48(uint64_t x0);
-  // compiler-generated copy ctor and assignment operator are fine
-  void seed(int32_t x0);
-  void seed(uint64_t x0);
-  int32_t operator()();
-};
-
- -

Description

- -Class rand48 models a -pseudo-random number -generator. It uses the linear congruential algorithm with the -parameters a = 0x5DEECE66D, c = 0xB, m = 2**48. It delivers identical -results to the lrand48() function available on some -systems (assuming lcong48 has not been called). -

-It is only available on systems where uint64_t is -provided as an integral type, so that for example static in-class -constants and/or enum definitions with large uint64_t -numbers work. - -

Constructors

- -
rand48(int32_t x0)
- -Effects: Constructs a rand48 generator -with x(0) := (x0 << 16) | 0x330e. - -
rand48(uint64_t x0)
- -Effects: Constructs a rand48 generator -with x(0) := x0. - -

Seeding

-
void seed(int32_t x0)
- -Effects: Changes the current value x(n) of the -generator to (x0 << 16) | 0x330e. - -
void seed(uint64_t x0)
- -Effects: Changes the current value x(n) of the -generator to x0. - - -

Class template -random::additive_combine

- -

Synopsis

- -
-#include <boost/random/additive_combine.hpp>
-
-template<class MLCG1, class MLCG2, typename MLCG1::result_type val>
-class random::additive_combine
-{
-public:
-  typedef MLCG1 first_base;
-  typedef MLCG2 second_base;
-  typedef typename MLCG1::result_type result_type;
-  static const bool has_fixed_range = true;
-  static const result_type min_value = 1;
-  static const result_type max_value = MLCG1::max_value-1;
-  additive_combine();
-  additive_combine(typename MLCG1::result_type seed1, 
-		   typename MLCG2::result_type seed2);
-  result_type operator()();
-  bool validation(result_type x) const;
-};
-
-typedef random::additive_combine<
-    random::linear_congruential<int32_t, 40014, 0, 2147483563, 0>,
-    random::linear_congruential<int32_t, 40692, 0, 2147483399, 0>,
-  /* unknown */ 0> ecuyer1988;
-
-
- -

Description

- -Instatiations of class template additive_combine model a -pseudo-random number -generator. It combines two multiplicative linear congruential -number generators, i.e. those with c = 0. It is described in -
-"Efficient and Portable Combined Random Number Generators", Pierre -L'Ecuyer, Communications of the ACM, Vol. 31, No. 6, June 1988, -pp. 742-749, 774 -
- -The template parameters MLCG1 and MLCG2 -shall denote two different linear congruential number generators, each -with c = 0. Each invocation returns a random number X(n) := (MLCG1(n) -- MLCG2(n)) mod (m1 - 1), where m1 denotes the modulus of -MLCG1. - -

-The template parameter val is the validation value -checked by validation. - - -

Members

- -
additive_combine()
- -Effects: Constructs an additive_combine -generator using the default constructors of the two base generators. - -
additive_combine(typename MLCG1::result_type seed1, 
- 		 typename MLCG2::result_type seed2)
- -Effects: Constructs an additive_combine -generator, using seed1 and seed2 as the -constructor argument to the first and second base generator, -respectively. - - -

Specialization

- -The specialization ecuyer1988 was suggested in the above -paper. - - -

Class template -random::shuffle_output

- -

Synopsis

- -
-#include <boost/random/shuffle_output.hpp>
-
-template<class UniformRandomNumberGenerator, int k, 
-  typename UniformRandomNumberGenerator::result_type val = 0>
-class random::shuffle_output
-{
-public:
-  typedef UniformRandomNumberGenerator base_type;
-  typedef typename base_type::result_type result_type;
-  static const bool has_fixed_range = false;
-
-  shuffle_output();
-  template<class T> explicit shuffle_output(T seed);
-  explicit shuffle_output(const base_type & rng);
-  template<class T> void seed(T s);
-
-  result_type operator()();
-  result_type min() const;
-  result_type max() const;
-  bool validation(result_type) const;
-};
-
- -

Description

- -Instatiations of class template shuffle_output model a -pseudo-random number -generator. It mixes the output of some (usually linear -congruential) uniform random number generator to get better -statistical properties. According to Donald E. Knuth, "The Art of -Computer Programming, Vol. 2", the algorithm is described in -
-"Improving a poor random number generator", Carter Bays and -S.D. Durham, ACM Transactions on Mathematical Software, Vol. 2, 1979, -pp. 59-64. -
-The output of the base generator is buffered in an array of length -k. Every output X(n) has a second role: It gives an index into the -array where X(n+1) will be retrieved. Used array elements are -replaced with fresh output from the base generator. - -

- -Template parameters are the base generator and the array length k, -which should be around 100. The template parameter -val is the validation value checked by -validation. - - -

Members

- -
shuffle_output()
- -Effects: Constructs a shuffle_output -generator by invoking the default constructor of the base generator. -

-Complexity: Exactly k+1 invocations of the base -generator. - -

template<class T> explicit shuffle_output(T seed)
- -Effects: Constructs a shuffle_output -generator by invoking the one-argument constructor of the base -generator with the parameter seed. -

-Complexity: Exactly k+1 invocations of the base -generator. - -

explicit shuffle_output(const base_type & rng)
- -Precondition: The template argument -UniformRandomNumberGenerator shall denote a -CopyConstructible type. -

-Effects: Constructs a shuffle_output -generator by using a copy of the provided generator. -

-Complexity: Exactly k+1 invocations of the base -generator. - -

template<class T> void seed(T s)
- -Effects: Invokes the one-argument seed -method of the base generator with the parameter seed and -re-initializes the internal buffer array. -

-Complexity: Exactly k+1 invocations of the base -generator. - - -

Specializations

- -According to Harry Erwin (private e-mail), the specialization -kreutzer1986 was suggested in: -
-"System Simulation: programming Styles and Languages (International -Computer Science Series)", Wolfgang Kreutzer, Addison-Wesley, December -1986. -
- - -

Class template -random::inversive_congruential

- -

Synopsis

- -
-#include <boost/random/inversive_congruential.hpp>
-
-template<class IntType, IntType a, IntType b, IntType p>
-class random::inversive_congruential
-{
-public:
-  typedef IntType result_type;
-  static const bool has_fixed_range = true;
-  static const result_type min_value = (b == 0 ? 1 : 0);
-  static const result_type max_value = p-1;
-  static const result_type multiplier = a;
-  static const result_type increment = b;
-  static const result_type modulus = p;
-  explicit inversive_congruential(IntType y0 = 1);
-  void seed(IntType y0);
-  IntType operator()();
-};
-
-typedef random::inversive_congruential<int32_t, 9102, 2147483647-36884165, 2147483647> hellekalek1995;
-
- -

Description

- -Instantiations of class template inversive_congruential model a -pseudo-random number -generator. It uses the inversive congruential algorithm (ICG) -described in -
-"Inversive pseudorandom number generators: concepts, results and -links", Peter Hellekalek, In: "Proceedings of the 1995 Winter -Simulation Conference", C. Alexopoulos, K. Kang, W.R. Lilegdon, and -D. Goldsman (editors), 1995, pp. 255-262. -ftp://random.mat.sbg.ac.at/pub/data/wsc95.ps -
- -The output sequence is defined by x(n+1) = (a*inv(x(n)) - b) (mod p), -where x(0), a, b, and the prime number p are parameters of the -generator. The expression inv(k) denotes the multiplicative inverse -of k in the field of integer numbers modulo p, with inv(0) := 0. - -

- -The template parameter IntType shall denote a signed -integral type large enough to hold p; a, b, and p are the parameters -of the generators. -

-Note: The implementation currently uses the Euclidian -Algorithm to compute the multiplicative inverse. Therefore, the -inversive generators are about 10-20 times slower than the others (see -section"performance"). However, the paper -talks of only 3x slowdown, so the Euclidian Algorithm is probably not -optimal for calculating the multiplicative inverse. - - -

Members

- -
inversive_congruential(IntType y0 = 1)
- -Effects: Constructs an -inversive_congruential generator with -y0 as the initial state. - -
void seed(IntType y0)
- -Effects: -Changes the current state to y0. - - -

Specialization

- -The specialization hellekalek1995 was suggested in the -above paper. - - -

Class template -random::mersenne_twister

- -

Synopsis

- -
-#include <boost/random/mersenne_twister.hpp>
-
-template<class DataType, int w, int n, int m, int r, DataType a, int u,
-int s, DataType b, int t, DataType c, int l, IntType val>
-class random::mersenne_twister
-{
-public:
-  typedef DataType result_type;
-  static const bool has_fixed_range = true;
-  static const result_type min_value;
-  static const result_type max_value;
-  mersenne_twister();
-  explicit mersenne_twister(DataType value);
-  template<class Generator> explicit mersenne_twister(Generator & gen);
-  // compiler-generated copy ctor and assignment operator are fine
-  void seed();
-  void seed(DataType value);
-  template<class Generator> void seed(Generator & gen);
-  result_type operator()();
-  bool validation(result_type) const;
-};
-
-typedef mersenne_twister<uint32_t,351,175,19,0xccab8ee7,11,7,0x31b6ab00,15,0xffe50000,17, /* unknown */ 0> mt11213b;
-typedef mersenne_twister<uint32_t,624,397,31,0x9908b0df,11,7,0x9d2c5680,15,0xefc60000,18, 3346425566U> mt19937;
-
- -

Description

- -Instantiations of class template mersenne_twister model a -pseudo-random number -generator. It uses the algorithm described in - -
-"Mersenne Twister: A 623-dimensionally equidistributed uniform -pseudo-random number generator", Makoto Matsumoto and Takuji Nishimura, -ACM Transactions on Modeling and Computer Simulation: Special Issue -on Uniform Random Number Generation, Vol. 8, No. 1, January 1998, -pp. 3-30. -http://www.math.keio.ac.jp/matumoto/emt.html -
- -Note: The boost variant has been implemented from scratch -and does not derive from or use mt19937.c provided on the above WWW -site. However, it was verified that both produce identical output. -
-The quality of the generator crucially depends on the choice of the -parameters. User code should employ one of the sensibly parameterized -generators such as mt19937 instead. -
-The generator requires considerable amounts of memory for the storage -of its state array. For example, mt11213b requires about -1408 bytes and mt19937 requires about 2496 bytes. - -

Constructors

- -
mersenne_twister()
- -Effects: Constructs a mersenne_twister -and calls seed(). - -
explicit mersenne_twister(result_type value)
- -Effects: Constructs a mersenne_twister -and calls seed(value). - -
template<class Generator> explicit mersenne_twister(Generator & gen)
- -Effects: Constructs a mersenne_twister -and calls seed(gen). -

-Note: When using direct-initialization syntax with an lvalue -(e.g. in the variable definition Gen gen2(gen);), this -templated constructor will be preferred over the compiler-generated -copy constructor. For variable definitions which should copy the -state of another mersenne_twister, use e.g. Gen -gen2 = gen;, which is copy-initialization syntax and guaranteed -to invoke the copy constructor. - -

Seeding

- -
void seed()
- -Effects: Calls seed(result_type(4357)). - -
void seed(result_type value)
- -Effects: Constructs a -linear_congruential<uint32_t, 69069, 0, 0, 0> -generator with the constructor parameter -value and calls seed with it. - -
template<class Generator> void seed(Generator & gen)
- -Effects: Sets the state of this -mersenne_twister to the values returned by n -invocations of gen. - -

- -Complexity: Exactly n invocations of -gen. -

-Note: When invoking seed with an lvalue, -overload resolution chooses the function template unless the type of -the argument exactly matches result_type. For other -integer types, you should convert the argument to -result_type explicitly. - -

Specializations

- -The specializations mt11213b and mt19937 are -from the paper cited above. - -

Class template -random::lagged_fibonacci

- -

Synopsis

- -
-#include <boost/random/lagged_fibonacci.hpp>
-
-template<class FloatType, unsigned int p, unsigned int q>
-class lagged_fibonacci
-{
-public:
-  typedef FloatType result_type;
-  static const bool has_fixed_range = false;
-  static const unsigned int long_lag = p;
-  static const unsigned int short_lag = q;
-  result_type min() const { return 0.0; }
-  result_type max() const { return 1.0; }
-  lagged_fibonacci();
-  explicit lagged_fibonacci(uint32_t value);
-  template<class Generator>
-  explicit lagged_fibonacci(Generator & gen);
-  // compiler-generated copy ctor and assignment operator are fine
-  void seed(uint32_t value = 331u);
-  template<class Generator> void seed(Generator & gen);
-  result_type operator()();
-  bool validation(result_type x) const;
-};
-
-typedef random::lagged_fibonacci<double, 607, 273> lagged_fibonacci607;
-typedef random::lagged_fibonacci<double, 1279, 418> lagged_fibonacci1279;
-typedef random::lagged_fibonacci<double, 2281, 1252> lagged_fibonacci2281;
-typedef random::lagged_fibonacci<double, 3217, 576> lagged_fibonacci3217;
-typedef random::lagged_fibonacci<double, 4423, 2098> lagged_fibonacci4423;
-typedef random::lagged_fibonacci<double, 9689, 5502> lagged_fibonacci9689;
-typedef random::lagged_fibonacci<double, 19937, 9842> lagged_fibonacci19937;
-typedef random::lagged_fibonacci<double, 23209, 13470> lagged_fibonacci23209;
-typedef random::lagged_fibonacci<double, 44497, 21034> lagged_fibonacci44497;
-
- -

Description

- -Instantiations of class template lagged_fibonacci model a -pseudo-random number -generator. It uses a lagged Fibonacci algorithm with two lags p -and q, evaluated in floating-point arithmetic: x(i) = x(i-p) + x(i-q) -(mod 1) with p > q. See - -
-"Uniform random number generators for supercomputers", Richard Brent, -Proc. of Fifth Australian Supercomputer Conference, Melbourne, -Dec. 1992, pp. 704-706. -
- -

-Note: The quality of the generator crucially depends on the -choice of the parameters. User code should employ one of the sensibly -parameterized generators such as lagged_fibonacci607 -instead. -
-The generator requires considerable amounts of memory for the storage -of its state array. For example, lagged_fibonacci607 -requires about 4856 bytes and lagged_fibonacci44497 -requires about 350 KBytes. - -

Constructors

- -
lagged_fibonacci()
-Effects: Constructs a lagged_fibonacci -generator and calls seed(). - -
explicit lagged_fibonacci(uint32_t value)
-Effects: Constructs a lagged_fibonacci -generator and calls seed(value). - -
template<class Generator> explicit lagged_fibonacci(Generator & gen)
-Effects: Constructs a lagged_fibonacci -generator and calls seed(gen). - -

Seeding

- -
void seed()
-Effects: Calls seed(331u). - -
void seed(uint32_t value)
-Effects: Constructs a minstd_rand0 -generator with the constructor parameter value and calls -seed with it. - -
template<class Generator> void seed(Generator & gen)
-Effects: Sets the state of this -lagged_fibonacci to the values returned by p -invocations of uniform_01<gen, FloatType>. -
-Complexity: Exactly p invocations of -gen. - -

Specializations

-The specializations lagged_fibonacci607 -... lagged_fibonacci44497 (see above) use well tested -lags. (References will be added later.) - - -

Performance

- -The test program random_speed.cpp -measures the execution times of the -random.hpp implementation of the above -algorithms in a tight loop. The performance has been evaluated on a -Pentium Pro 200 MHz with gcc 2.95.2, Linux 2.2.13, glibc 2.1.2. - -

- - - - - - - - - - - - - - - - - - -
classtime per invocation [usec]
rand480.096
rand48 run-time configurable0.697
lrand48 glibc 2.1.20.844
minstd_rand0.174
ecuyer19880.445
kreutzer19860.249
hellekalek1995 (inversive)4.895
mt11213b0.165
mt199370.165
mt19937 original0.185
lagged_fibonacci6070.111
lagged_fibonacci44230.112
lagged_fibonacci199370.113
lagged_fibonacci232090.122
lagged_fibonacci444970.263
- -

-The measurement error is estimated at +/- 10 nsec. - -

-


-Jens Maurer, 2001-04-15 - - - diff --git a/random-misc.html b/random-misc.html deleted file mode 100644 index 86fefba..0000000 --- a/random-misc.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - -Boost Random Number Generator Library (Miscellaneous) - - - - -

Random Number Generator Library --- Miscellaneous Decorators

- - - -

Introduction

- -These decorator class templates allow adaptation of the random number -generators and distribution functions to concepts found in the C++ -Standard Library, in particular the RandomNumberGenerator and the -InputIterator concepts. The latter adaptation is useful, because the -the basic random number generators do not implement the InputIterator -requirements per se, in contrast to the distribution functions. - - -

Synopsis of miscellaneous decorators in -header <boost/random.hpp>

- -
-namespace boost {
-  template<class UniformRandomNumberGenerator, class IntType = long>
-  class random_number_generator;
-  template<class Generator>
-  class generator_iterator;
-} // namespace boost
-
- - -

Class template -random_number_generator

- -

Synopsis

-
-template<class UniformRandomNumberGenerator, class IntType = long>
-class random_number_generator
-{
-public:
-  typedef UniformRandomNumberGenerator base_type;
-  typedef IntType argument_type;
-  typedef IntType result_type;
-  random_number_generator(base_type & rng);
-  result_type operator()(argument_type n);
-};
-
- -

Description

- -Instantiations of class template random_number_generator -model a RandomNumberGenerator (std:25.2.11 [lib.alg.random.shuffle]). -On each invocation, it returns a uniformly distributed integer in -the range [0..n). -

-The template parameter IntType shall denote some -integer-like value type. -

- -Note: I consider it unfortunate that the C++ Standard uses -the name RandomNumberGenerator for something rather specific. - -

Members

- -
random_number_generator(base_type & rng)
- -Effects: Constructs a -random_number_generator functor with the given uniform -random number generator as the underlying source of random numbers. - -
result_type operator()(argument_type n)
- -Returns: The value of -uniform_int<base_type>(rng, 0, n-1)(). - -

-


-Jens Maurer, 2001-11-19 - - - diff --git a/random-performance.html b/random-performance.html deleted file mode 100644 index 0ec52f3..0000000 --- a/random-performance.html +++ /dev/null @@ -1,241 +0,0 @@ - - - - -Boost Random Number Library Performance - - - - -

Random Number Library Performance

- -For some people, performance of random number generation is an -important consideration when choosing a random number generator or a -particular distribution function. This page provides numerous -performance tests with the wide variety of generators and -distributions available in the boost library. -

-The performance has been evaluated on a Pentium Pro 200 MHz with gcc -2.95.2, Linux 2.2.13, glibc 2.1.2. The speed is reported in million -random numbers per second (M rn/sec), generated in a tight loop. -

- - -

Basic Generators

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
generatorM rn/sectime per random number [usec]relative speed compared to fastest [percent]
rand485.380.18361%
rand48 run-time configurable1.480.67717%
lrand48 glibc 2.1.21.190.84313%
minstd_rand2.390.31835%
ecuyer19881.120.89213%
kreutzer19863.870.25843%
hellekalek1995 (inversive)0.205.122%
mt11213b6.070.16568%
mt199376.060.16568%
mt19937 original5.330.18860%
lagged_fibonacci6078.900.112100%
lagged_fibonacci44238.540.11796%
lagged_fibonacci199377.490.13384%
lagged_fibonacci232096.630.15174%
lagged_fibonacci444974.010.25045%
-

-Note that the lagged Fibonacci generators produce floating-point -numbers, whereas all others produce integers. - -

Distributions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[M rn/sec]minstd_randkreutzer1986mt19937lagged_fibonacci607
uniform_smallint1.261.551.93-
uniform_011.791.883.037.74
uniform_real1.741.562.346.62
geometric0.5930.6290.7530.916
triangle0.971.021.351.31
exponential0.8490.8280.8871.53
normal (polar method)0.6080.6260.7380.755
lognormal0.4170.4420.4700.481
uniform_on_sphere0.1540.1550.1740.218
-

-Note that the lagged Fibonacci generator is at least 2.5 times faster -than the Mersenne twister when generating uniformly distributed -floating-point numbers. For more sophisticated distributions, the -speed improvement is less. Note however that these distributions have -not been optimized for speed, yet. -

-


-Jens Maurer, 2001-04-15 - - - diff --git a/random-variate.html b/random-variate.html deleted file mode 100644 index 6097fc1..0000000 --- a/random-variate.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - - -Boost Random Number Library Variate Generator - - - - -

Boost Random Number Library Variate Generator

- -A random variate generator is used to join a random number generator -together with a random number distribution. -Boost.Random provides a vast choice of -generators -as well as -distributions -. - - -

Class template variate_generator

- -

Synopsis

-
-#include <boost/random/variate_generator.hpp>
-
-template<class Engine, class Distribution>
-class variate_generator
-{
-public:
-  typedef Engine engine_type;
-  typedef Distribution distribution_type;
-  typedef typename Distribution::result_type result_type;
-
-  variate_generator(Engine e, Distribution d);
-
-  result_type operator()();
-  template<class T>
-  result_type operator()(T value);
-  
-  engine_value_type& engine();
-  const engine_value_type& engine() const;
-
-  result_type min() const;
-  result_type max() const;
-};
-
- -

Description

- -Instantations of class template variate_generator model a -number generator. -

-The argument for the template parameter Engine shall be -of the form U, U&, or U*, where U models a uniform random number -generator. Then, the member engine_value_type names U -(not the pointer or reference to U). -

- -Specializations of variate_generator satisfy the -requirements of CopyConstructible. They also satisfy the requirements -of Assignable unless the template parameter Engine is of the form U&. -

- -The complexity of all functions specified in this section is -constant. No function described in this section except the constructor -throws an exception. - -

    variate_generator(engine_type eng, distribution_type d)
-Effects: Constructs a variate_generator -object with the associated uniform random number generator -eng and the associated random distribution -d. -
-Throws: If and what the copy constructor of Engine or -Distribution throws. - -
    result_type operator()()
-Returns: distribution()(e) -
-Notes: The sequence of numbers produced by the -uniform random number generator e, se, is -obtained from the sequence of numbers produced by the associated -uniform random number generator eng, seng, as -follows: Consider the values of -numeric_limits<T>::is_integer for -T both Distribution::input_type and -engine_value_type::result_type. If the values for both -types are true, then se is identical to -seng. Otherwise, if the values for both types are -false, then the numbers in seng are divided by -engine().max()-engine().min() to obtain the -numbers in se. Otherwise, if the value for -engine_value_type::result_type is true and -the value for Distribution::input_type is -false, then the numbers in seng are divided by -engine().max()-engine().min()+1 to obtain the -numbers in se. Otherwise, the mapping from seng -to se is implementation-defined. In all cases, an implicit -conversion from engine_value_type::result_type to -Distribution::input_type is performed. If such a -conversion does not exist, the program is ill-formed. - -
    template<class T> result_type operator()(T value)
-Returns: distribution()(e, value). For -the semantics of e, see the description of -operator()(). - -
    engine_value_type& engine()
-Returns: A reference to the associated uniform random -number generator. - -
    const engine_value_type& engine() const
-Returns: A reference to the associated uniform random -number generator. - -
    distribution_type& distribution()
-Returns: A reference to the associated random -distribution. - -
    const distribution_type& distribution() const
-Returns: A reference to the associated random -distribution. - -
    result_type min() const
-Precondition: distribution().min() is -well-formed -
-Returns: distribution().min() - -
    result_type max() const
-Precondition: distribution().max() is -well-formed -
-Returns: distribution().max() - -

-


-Jens Maurer, -2003-10-25 - - - diff --git a/random_demo.cpp b/random_demo.cpp deleted file mode 100644 index c506cea..0000000 --- a/random_demo.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* boost random_demo.cpp profane demo - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - * A short demo program how to use the random number library. - */ - -#include -#include -#include // std::time - -#include -#include -#include -#include - -// Sun CC doesn't handle boost::iterator_adaptor yet -#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530) -#include -#endif - -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std { - using ::time; -} -#endif - -// This is a typedef for a random number generator. -// Try boost::mt19937 or boost::ecuyer1988 instead of boost::minstd_rand -typedef boost::minstd_rand base_generator_type; - -// This is a reproducible simulation experiment. See main(). -void experiment(base_generator_type & generator) -{ - // Define a uniform random number distribution of integer values between - // 1 and 6 inclusive. - typedef boost::uniform_int<> distribution_type; - typedef boost::variate_generator gen_type; - gen_type die_gen(generator, distribution_type(1, 6)); - -#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530) - // If you want to use an STL iterator interface, use iterator_adaptors.hpp. - // Unfortunately, this doesn't work on SunCC yet. - boost::generator_iterator die(&die_gen); - for(int i = 0; i < 10; i++) - std::cout << *die++ << " "; - std::cout << '\n'; -#endif -} - -int main() -{ - // Define a random number generator and initialize it with a reproducible - // seed. - // (The seed is unsigned, otherwise the wrong overload may be selected - // when using mt19937 as the base_generator_type.) - base_generator_type generator(42u); - - std::cout << "10 samples of a uniform distribution in [0..1):\n"; - - // Define a uniform random number distribution which produces "double" - // values between 0 and 1 (0 inclusive, 1 exclusive). - boost::uniform_real<> uni_dist(0,1); - boost::variate_generator > uni(generator, uni_dist); - - std::cout.setf(std::ios::fixed); - // You can now retrieve random numbers from that distribution by means - // of a STL Generator interface, i.e. calling the generator as a zero- - // argument function. - for(int i = 0; i < 10; i++) - std::cout << uni() << '\n'; - - /* - * Change seed to something else. - * - * Caveat: std::time(0) is not a very good truly-random seed. When - * called in rapid succession, it could return the same values, and - * thus the same random number sequences could ensue. If not the same - * values are returned, the values differ only slightly in the - * lowest bits. A linear congruential generator with a small factor - * wrapped in a uniform_smallint (see experiment) will produce the same - * values for the first few iterations. This is because uniform_smallint - * takes only the highest bits of the generator, and the generator itself - * needs a few iterations to spread the initial entropy from the lowest bits - * to the whole state. - */ - generator.seed(static_cast(std::time(0))); - - std::cout << "\nexperiment: roll a die 10 times:\n"; - - // You can save a generator's state by copy construction. - base_generator_type saved_generator = generator; - - // When calling other functions which take a generator or distribution - // as a parameter, make sure to always call by reference (or pointer). - // Calling by value invokes the copy constructor, which means that the - // sequence of random numbers at the caller is disconnected from the - // sequence at the callee. - experiment(generator); - - std::cout << "redo the experiment to verify it:\n"; - experiment(saved_generator); - - // After that, both generators are equivalent - assert(generator == saved_generator); - - // as a degenerate case, you can set min = max for uniform_int - boost::uniform_int<> degen_dist(4,4); - boost::variate_generator > deg(generator, degen_dist); - std::cout << deg() << " " << deg() << " " << deg() << std::endl; - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE - { - // You can save the generator state for future use. You can read the - // state back in at any later time using operator>>. - std::ofstream file("rng.saved", std::ofstream::trunc); - file << generator; - } -#endif - // Some compilers don't pay attention to std:3.6.1/5 and issue a - // warning here if "return 0;" is omitted. - return 0; -} diff --git a/random_device.cpp b/random_device.cpp deleted file mode 100644 index 95d7348..0000000 --- a/random_device.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* boost random_device.cpp implementation - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - */ - -#include -#include -#include - - -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION -// A definition is required even for integral static constants -const bool boost::random_device::has_fixed_range; -const boost::random_device::result_type boost::random_device::min_value; -const boost::random_device::result_type boost::random_device::max_value; -#endif - - -#ifdef __linux__ - -// the default is the unlimited capacity device, using some secure hash -// try "/dev/random" for blocking when the entropy pool has drained -const char * const boost::random_device::default_token = "/dev/urandom"; - -/* - * This uses the POSIX interface for unbuffered reading. - * Using buffered std::istream would consume entropy which may - * not actually be used. Entropy is a precious good we avoid - * wasting. - */ - -#if defined(__GNUC__) && defined(_CXXRT_STD_NAME) -// I have severe difficulty to get the POSIX includes to work with -// -fhonor-std and Dietmar Kühl's standard C++ library. Hack around that -// problem for now. -extern "C" { -static const int O_RDONLY = 0; -extern int open(const char *__file, int __oflag, ...); -extern int read(int __fd, __ptr_t __buf, size_t __nbytes); -extern int close(int __fd); -} -#else -#include -#include -#include // open -#include // read, close -#endif - -#include // errno -#include // strerror -#include // std::invalid_argument - - -class boost::random_device::impl -{ -public: - impl(const std::string & token) : path(token) { - fd = open(token.c_str(), O_RDONLY); - if(fd < 0) - error("cannot open"); - } - - ~impl() { if(close(fd) < 0) error("could not close"); } - - unsigned int next() { - unsigned int result; - long sz = read(fd, reinterpret_cast(&result), sizeof(result)); - if(sz == -1) - error("error while reading"); - else if(sz != sizeof(result)) { - errno = 0; - error("EOF while reading"); - } - return result; - } - -private: - void error(const std::string & msg) { - throw std::invalid_argument("boost::random_device: " + msg + - " random-number pseudo-device " + path + - ": " + strerror(errno)); - } - const std::string path; - int fd; -}; - -#endif // __linux__ - - -boost::random_device::random_device(const std::string& token) - : pimpl(new impl(token)) -{ - assert((std::numeric_limits::max)() == max_value); -} - -boost::random_device::~random_device() -{ - // the complete class impl is now visible, so we're safe - // (see comment in random.hpp) - delete pimpl; -} - -double boost::random_device::entropy() const -{ - return 10; -} - -unsigned int boost::random_device::operator()() -{ - return pimpl->next(); -} diff --git a/random_speed.cpp b/random_speed.cpp deleted file mode 100644 index f20ba1b..0000000 --- a/random_speed.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* boost random_speed.cpp performance measurements - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Configuration Section - */ - -// define if your C library supports the non-standard drand48 family -#undef HAVE_DRAND48 - -// define if you have the original mt19937int.c (with commented out main()) -#undef HAVE_MT19937INT_C - -// set to your CPU frequency in MHz -static const double cpu_frequency = 200 * 1e6; - -/* - * End of Configuration Section - */ - -/* - * General portability note: - * MSVC mis-compiles explicit function template instantiations. - * For example, f() and f() are both compiled to call f(). - * BCC is unable to implicitly convert a "const char *" to a std::string - * when using explicit function template instantiations. - * - * Therefore, avoid explicit function template instantiations. - */ - -// provides a run-time configurable linear congruential generator, just -// for comparison -template -class linear_congruential -{ -public: - typedef IntType result_type; - - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - - linear_congruential(IntType x0, IntType a, IntType c, IntType m) - : _x(x0), _a(a), _c(c), _m(m) { } - // compiler-generated copy ctor and assignment operator are fine - void seed(IntType x0, IntType a, IntType c, IntType m) - { _x = x0; _a = a; _c = c; _m = m; } - void seed(IntType x0) { _x = x0; } - result_type operator()() { _x = (_a*_x+_c) % _m; return _x; } - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _c == 0 ? 1 : 0; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _m -1; } - -private: - IntType _x, _a, _c, _m; -}; - - -// simplest "random" number generator possible, to check on overhead -class counting -{ -public: - typedef int result_type; - - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - - counting() : _x(0) { } - result_type operator()() { return ++_x; } - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 1; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::numeric_limits::max)(); } - -private: - int _x; -}; - - -// decoration of variate_generator to make it runtime-exchangeable -// for speed comparison -template -class RandomGenBase -{ -public: - virtual Ret operator()() = 0; - virtual ~RandomGenBase() { } -}; - -template -class DynamicRandomGenerator - : public RandomGenBase -{ -public: - DynamicRandomGenerator(URNG& urng, const Dist& d) : _rng(urng, d) { } - Ret operator()() { return _rng(); } -private: - boost::variate_generator _rng; -}; - -template -class GenericRandomGenerator -{ -public: - typedef Ret result_type; - - GenericRandomGenerator() { }; - void set(boost::shared_ptr > p) { _p = p; } - // takes over ownership - void set(RandomGenBase * p) { _p.reset(p); } - Ret operator()() { return (*_p)(); } -private: - boost::shared_ptr > _p; -}; - - -// start implementation of measuring timing - -void show_elapsed(double end, int iter, const std::string & name) -{ - double usec = end/iter*1e6; - double cycles = usec * cpu_frequency/1e6; - std::cout << name << ": " - << usec*1e3 << " nsec/loop = " - << cycles << " CPU cycles" - << std::endl; -} - -#if 0 -template -void timing(RNG & rng, int iter, const std::string& name) -{ - // make sure we're not optimizing too much - volatile typename RNG::result_type tmp; - boost::timer t; - for(int i = 0; i < iter; i++) - tmp = rng(); - show_elapsed(t.elapsed(), iter, name); -} -#endif - -// overload for using a copy, allows more concise invocation -template -void timing(RNG rng, int iter, const std::string& name) -{ - // make sure we're not optimizing too much - volatile typename RNG::result_type tmp; - boost::timer t; - for(int i = 0; i < iter; i++) - tmp = rng(); - show_elapsed(t.elapsed(), iter, name); -} - -template -void timing_sphere(RNG rng, int iter, const std::string & name) -{ - boost::timer t; - for(int i = 0; i < iter; i++) { - // the special return value convention of uniform_on_sphere saves 20% CPU - const std::vector & tmp = rng(); - (void) tmp[0]; - } - show_elapsed(t.elapsed(), iter, name); -} - -template -void run(int iter, const std::string & name, const RNG &) -{ - std::cout << (RNG::has_fixed_range ? "fixed-range " : ""); - // BCC has trouble with string autoconversion for explicit specializations - timing(RNG(), iter, std::string(name)); -} - -#ifdef HAVE_DRAND48 -// requires non-standard C library support for srand48/lrand48 -void run(int iter, const std::string & name, int) -{ - std::srand48(1); - timing(&std::lrand48, iter, name); -} -#endif - -#ifdef HAVE_MT19937INT_C // requires the original mt19937int.c -extern "C" void sgenrand(unsigned long); -extern "C" unsigned long genrand(); - -void run(int iter, const std::string & name, float) -{ - sgenrand(4357); - timing(genrand, iter, name, 0u); -} -#endif - -template -inline boost::variate_generator make_gen(PRNG & rng, Dist d) -{ - return boost::variate_generator(rng, d); -} - -template -void distrib(int iter, const std::string & name, const Gen &) -{ - Gen gen; - - timing(make_gen(gen, boost::uniform_int<>(-2, 4)), - iter, name + " uniform_int"); - - timing(make_gen(gen, boost::geometric_distribution<>(0.5)), - iter, name + " geometric"); - - timing(make_gen(gen, boost::binomial_distribution(4, 0.8)), - iter, name + " binomial"); - - timing(make_gen(gen, boost::poisson_distribution<>(1)), - iter, name + " poisson"); - - - timing(make_gen(gen, boost::uniform_real<>(-5.3, 4.8)), - iter, name + " uniform_real"); - - timing(make_gen(gen, boost::triangle_distribution<>(1, 2, 7)), - iter, name + " triangle"); - - timing(make_gen(gen, boost::exponential_distribution<>(3)), - iter, name + " exponential"); - - timing(make_gen(gen, boost::normal_distribution<>()), - iter, name + " normal polar"); - - timing(make_gen(gen, boost::lognormal_distribution<>()), - iter, name + " lognormal"); - - timing(make_gen(gen, boost::cauchy_distribution<>()), - iter, name + " cauchy"); - - timing(make_gen(gen, boost::cauchy_distribution<>()), - iter, name + " gamma"); - - timing_sphere(make_gen(gen, boost::uniform_on_sphere<>(3)), - iter/10, name + " uniform_on_sphere"); -} - - -template -inline boost::shared_ptr > -make_dynamic(URNG & rng, const Dist& d) -{ - typedef DynamicRandomGenerator type; - return boost::shared_ptr(new type(rng, d)); -} - -template -void distrib_runtime(int iter, const std::string & n, const Gen &) -{ - std::string name = n + " virtual function "; - Gen gen; - - GenericRandomGenerator g_int; - - g_int.set(make_dynamic(gen, boost::uniform_int<>(-2,4))); - timing(g_int, iter, name + "uniform_int"); - - g_int.set(make_dynamic(gen, boost::geometric_distribution<>(0.5))); - timing(g_int, iter, name + "geometric"); - - g_int.set(make_dynamic(gen, boost::binomial_distribution<>(4, 0.8))); - timing(g_int, iter, name + "binomial"); - - g_int.set(make_dynamic(gen, boost::poisson_distribution<>(1))); - timing(g_int, iter, name + "poisson"); - - GenericRandomGenerator g; - - g.set(make_dynamic(gen, boost::uniform_real<>(-5.3, 4.8))); - timing(g, iter, name + "uniform_real"); - - g.set(make_dynamic(gen, boost::triangle_distribution<>(1, 2, 7))); - timing(g, iter, name + "triangle"); - - g.set(make_dynamic(gen, boost::exponential_distribution<>(3))); - timing(g, iter, name + "exponential"); - - g.set(make_dynamic(gen, boost::normal_distribution<>())); - timing(g, iter, name + "normal polar"); - - g.set(make_dynamic(gen, boost::lognormal_distribution<>())); - timing(g, iter, name + "lognormal"); - - g.set(make_dynamic(gen, boost::cauchy_distribution<>())); - timing(g, iter, name + "cauchy"); - - g.set(make_dynamic(gen, boost::gamma_distribution<>(0.4))); - timing(g, iter, name + "gamma"); -} - - -int main(int argc, char*argv[]) -{ - if(argc != 2) { - std::cerr << "usage: " << argv[0] << " iterations" << std::endl; - return 1; - } - - // okay, it's ugly, but it's only used here - int iter = -#ifndef BOOST_NO_STDC_NAMESPACE - std:: -#endif - atoi(argv[1]); - -#if !defined(BOOST_NO_INT64_T) && \ - !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) - run(iter, "rand48", boost::rand48()); - linear_congruential - lcg48(boost::uint64_t(1)<<16 | 0x330e, - boost::uint64_t(0xDEECE66DUL) | (boost::uint64_t(0x5) << 32), 0xB, - boost::uint64_t(1)<<48); - timing(lcg48, iter, "lrand48 run-time"); -#endif - -#ifdef HAVE_DRAND48 - // requires non-standard C library support for srand48/lrand48 - run(iter, "lrand48", 0); // coded for lrand48() -#endif - - run(iter, "minstd_rand", boost::minstd_rand()); - run(iter, "ecuyer combined", boost::ecuyer1988()); - run(iter, "kreutzer1986", boost::kreutzer1986()); - - run(iter, "hellekalek1995 (inversive)", boost::hellekalek1995()); - - run(iter, "mt11213b", boost::mt11213b()); - run(iter, "mt19937", boost::mt19937()); - - run(iter, "subtract_with_carry", boost::random::ranlux_base()); - run(iter, "subtract_with_carry_01", boost::random::ranlux_base_01()); - run(iter, "ranlux3", boost::ranlux3()); - run(iter, "ranlux4", boost::ranlux4()); - run(iter, "ranlux3_01", boost::ranlux3_01()); - run(iter, "ranlux4_01", boost::ranlux4_01()); - run(iter, "counting", counting()); - -#ifdef HAVE_MT19937INT_C - // requires the original mt19937int.c - run(iter, "mt19937 original"); // coded for sgenrand()/genrand() -#endif - - distrib(iter, "counting", counting()); - distrib_runtime(iter, "counting", counting()); - - distrib(iter, "minstd_rand", boost::minstd_rand()); - - distrib(iter, "kreutzer1986", boost::kreutzer1986()); - - distrib(iter, "mt19937", boost::mt19937()); - distrib_runtime(iter, "mt19937", boost::mt19937()); -} diff --git a/random_test.cpp b/random_test.cpp deleted file mode 100644 index b1c69de..0000000 --- a/random_test.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* boost random_test.cpp various tests - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - */ - -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::abs; using ::fabs; using ::pow; } -#endif - - -/* - * General portability note: - * MSVC mis-compiles explicit function template instantiations. - * For example, f() and f() are both compiled to call f(). - * BCC is unable to implicitly convert a "const char *" to a std::string - * when using explicit function template instantiations. - * - * Therefore, avoid explicit function template instantiations. - */ - -/* - * Validate correct implementation - */ - -// own run -bool check(unsigned long x, const boost::mt11213b&) { return x == 0xa37d3c92; } - -// validation by experiment from mt19937.c -bool check(unsigned long x, const boost::mt19937&) { return x == 3346425566U; } - -// validation values from the publications -bool check(int x, const boost::minstd_rand0&) { return x == 1043618065; } - -// validation values from the publications -bool check(int x, const boost::minstd_rand&) { return x == 399268537; } - -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -// by experiment from lrand48() -bool check(unsigned long x, const boost::rand48&) { return x == 1993516219; } -#endif - -// ???? -bool check(unsigned long x, const boost::taus88&) { return x == 3535848941U; } - -// ???? -bool check(int x, const boost::ecuyer1988&) { return x == 2060321752; } - -// validation by experiment from Harry Erwin's generator.h (private e-mail) -bool check(unsigned int x, const boost::kreutzer1986&) { return x == 139726; } - -bool check(double x, const boost::lagged_fibonacci607&) { return std::abs(x-0.401269) < 1e-5; } - -// principal operation validated with CLHEP, values by experiment -bool check(unsigned long x, const boost::ranlux3&) { return x == 5957620; } -bool check(unsigned long x, const boost::ranlux4&) { return x == 8587295; } - -bool check(float x, const boost::ranlux3_01&) -{ return std::abs(x-5957620/std::pow(2.0f,24)) < 1e-6; } -bool check(float x, const boost::ranlux4_01&) -{ return std::abs(x-8587295/std::pow(2.0f,24)) < 1e-6; } - -bool check(double x, const boost::ranlux64_3_01&) -{ return std::abs(x-0.838413) < 1e-6; } -bool check(double x, const boost::ranlux64_4_01&) -{ return std::abs(x-0.59839) < 1e-6; } - -template -void validate(const std::string & name, const PRNG &) -{ - std::cout << "validating " << name << ": "; - PRNG rng; // default ctor - for(int i = 0; i < 9999; i++) - rng(); - typename PRNG::result_type val = rng(); - // make sure the validation function is a static member - bool result = check(val, rng); - - // allow for a simple eyeball check for MSVC instantiation brokenness - // (if the numbers for all generators are the same, it's obviously broken) - std::cout << val << std::endl; - BOOST_TEST(result); -} - -void validate_all() -{ - using namespace boost; -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) - validate("rand48", rand48()); -#endif - validate("minstd_rand", minstd_rand()); - validate("minstd_rand0", minstd_rand0()); - validate("ecuyer combined", ecuyer1988()); - validate("mt11213b", mt11213b()); - validate("mt19937", mt19937()); - validate("kreutzer1986", kreutzer1986()); - validate("ranlux3", ranlux3()); - validate("ranlux4", ranlux4()); - validate("ranlux3_01", ranlux3_01()); - validate("ranlux4_01", ranlux4_01()); - validate("ranlux64_3_01", ranlux64_3_01()); - validate("ranlux64_4_01", ranlux64_4_01()); - validate("taus88", taus88()); - validate("lagged_fibonacci607", lagged_fibonacci607()); -} - - -/* - * Check function signatures - */ - -template -void instantiate_dist(URNG& urng, const char * name, const Dist& dist) -{ - // this makes a copy of urng - boost::variate_generator gen(urng, dist); - - // this keeps a reference to urng - boost::variate_generator genref(urng, dist); - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - // and here is a pointer to (a copy of) the urng - URNG copy = urng; - boost::variate_generator genptr(©, dist); -#endif - - for(int i = 0; i < 1000; ++i) { - (void) gen(); - (void) genref(); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - (void) genptr(); -#endif - } - typename Dist::result_type g = gen(); - BOOST_CHECK(std::abs(g - genref()) < 1e-6); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - BOOST_CHECK(std::abs(g - genptr()) < 1e-6); -#endif - - (void) gen.engine(); - gen.distribution().reset(); - - Dist d = dist; // copy ctor - d = dist; // copy assignment - -#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - { - std::ostringstream file; - file << urng << std::endl; - file << d; - std::istringstream input(file.str()); - // std::cout << file.str() << std::endl; - URNG restored_engine; - input >> restored_engine; - input >> std::ws; - Dist restored_dist; - input >> restored_dist; -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - boost::variate_generator old(urng, d); - boost::variate_generator restored(restored_engine, restored_dist); - // advance some more so that state is exercised - for(int i = 0; i < 1000; ++i) { - (void) old(); - (void) restored(); - } - BOOST_CHECK_MESSAGE((std::abs(old()-restored()) < 0.0001), - (std::string(name) + " old == restored_dist")); -#endif // BOOST_MSVC - } -#endif // BOOST_NO_OPERATORS_IN_NAMESPACE -} - -template -void instantiate_real_dist(URNG& urng, RealType /* ignored */) -{ - instantiate_dist(urng, "uniform_real", - boost::uniform_real(0, 2.1)); - instantiate_dist(urng, "triangle_distribution", - boost::triangle_distribution(1, 1.5, 7)); - instantiate_dist(urng, "exponential_distribution", - boost::exponential_distribution(5)); - instantiate_dist(urng, "normal_distribution", - boost::normal_distribution()); - instantiate_dist(urng, "lognormal_distribution", - boost::lognormal_distribution(1, 1)); - instantiate_dist(urng, "cauchy_distribution", - boost::cauchy_distribution(1)); - instantiate_dist(urng, "gamma_distribution", - boost::gamma_distribution(1)); -} - -template -void instantiate_urng(const std::string & s, const URNG &, const ResultType &) -{ - std::cout << "Basic tests for " << s; - URNG urng; - urng.seed(); // seed() member function - int a[URNG::has_fixed_range ? 5 : 10]; // compile-time constant - (void) a; // avoid "unused" warning - typename URNG::result_type x1 = urng(); - ResultType x2 = x1; - (void) &x2; // avoid "unused" warning - - URNG urng2 = urng; // copy constructor -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - BOOST_TEST(urng == urng2); // operator== - BOOST_TEST(!(urng != urng2)); // operator!= - urng(); - urng2 = urng; // copy assignment - BOOST_TEST(urng == urng2); -#endif // BOOST_MSVC - - const std::vector v(9999u, 0x41); - std::vector::const_iterator it = v.begin(); - std::vector::const_iterator it_end = v.end(); - URNG urng3(it, it_end); - BOOST_TEST(it != v.begin()); - std::cout << "; seeding uses " << (it - v.begin()) << " words" << std::endl; - - bool have_exception = false; - try { - // now check that exceptions are thrown - it = v.end(); - urng3.seed(it, it_end); - } catch(std::invalid_argument& x) { - have_exception = true; - } - BOOST_TEST(have_exception); - - // check for min/max members - ResultType min = (urng3.min)(); - (void) &min; - ResultType max = (urng3.max)(); - (void) &max; - -#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - // Streamable concept not supported for broken compilers - - // advance a little so that state is relatively arbitrary - for(int i = 0; i < 9307; ++i) - urng(); - urng2 = urng; - - { - // narrow stream first - std::ostringstream file; - file << urng; - // move forward - urng(); - // restore old state - std::istringstream input(file.str()); - input >> urng; - // std::cout << file.str() << std::endl; -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - // advance some more so that state is exercised - for(int i = 0; i < 10000; ++i) { - urng(); - urng2(); - } - BOOST_TEST(urng == urng2); -#endif // BOOST_MSVC - } - - urng2 = urng; -#if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING) - { - // then wide stream - std::wostringstream file; - file << urng; - // move forward - urng(); - std::wistringstream input(file.str()); - input >> urng; -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - // advance some more so that state is exercised - for(int i = 0; i < 10000; ++i) { - urng(); - urng2(); - } - BOOST_TEST(urng == urng2); -#endif // BOOST_MSVC - } -#endif // BOOST_NO_STD_WSTREAMBUF, BOOST_NO_STD_WSTRING -#endif // BOOST_NO_OPERATORS_IN_NAMESPACE etc. - - // instantiate various distributions with this URNG - // instantiate_dist(urng, "uniform_smallint", boost::uniform_smallint(0, 11)); - instantiate_dist(urng, "uniform_int", boost::uniform_int<>(-200, 20000)); - instantiate_dist(urng, "bernoulli_distribution", - boost::bernoulli_distribution<>(0.2)); - instantiate_dist(urng, "binomial_distribution", - boost::binomial_distribution<>(4, 0.2)); - instantiate_dist(urng, "geometric_distribution", - boost::geometric_distribution<>(0.8)); - instantiate_dist(urng, "poisson_distribution", - boost::poisson_distribution<>(1)); - - instantiate_real_dist(urng, 1.0f); - instantiate_real_dist(urng, 1.0); - instantiate_real_dist(urng, 1.0l); - -#if 0 - // We cannot compare the outcomes before/after save with std::abs(x-y) - instantiate_dist("uniform_on_sphere", - boost::uniform_on_sphere(urng, 2)); -#endif -} - -void instantiate_all() -{ - using namespace boost; - -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) - instantiate_urng("rand48", rand48(), 0); - rand48 rnd(boost::int32_t(5)); - rand48 rnd2(boost::uint64_t(0x80000000) * 42); - rnd.seed(boost::int32_t(17)); - rnd2.seed(boost::uint64_t(0x80000000) * 49); -#endif - - instantiate_urng("minstd_rand0", minstd_rand0(), 0); - instantiate_urng("minstd_rand", minstd_rand(), 0); - minstd_rand mstd(42); - mstd.seed(17); - - instantiate_urng("ecuyer1988", ecuyer1988(), 0); - instantiate_urng("kreutzer1986", kreutzer1986(), 0); - instantiate_urng("hellekalek1995", hellekalek1995(), 0); - - instantiate_urng("mt11213b", mt11213b(), 0u); - instantiate_urng("mt19937", mt19937(), 0u); - - mt19937 mt(boost::uint32_t(17)); // needs to be an exact type match for MSVC - int i = 42; - mt.seed(boost::uint32_t(i)); - mt19937 mt2(mstd); - mt2.seed(mstd); - - - random_number_generator std_rng(mt2); - (void) std_rng(10); - - instantiate_urng("lagged_fibonacci", - boost::random::lagged_fibonacci(), - 0u); - instantiate_urng("lagged_fibonacci607", lagged_fibonacci607(), 0.0); - - instantiate_urng("ranlux3", ranlux3(), 0u); - instantiate_urng("ranlux4", ranlux4(), 0u); - - instantiate_urng("ranlux3_01", ranlux3_01(), 0.0f); - instantiate_urng("ranlux4_01", ranlux4_01(), 0.0f); - - instantiate_urng("ranlux64_3_01", ranlux64_3_01(), 0.0); - instantiate_urng("ranlux64_4_01", ranlux64_4_01(), 0.0); - - instantiate_urng("taus88", taus88(), 0u); -} - -/* - * A few equidistribution tests - */ - -// yet to come... - -template -void check_uniform_int(Generator & gen, int iter) -{ - std::cout << "testing uniform_int(" << (gen.min)() << "," << (gen.max)() - << ")" << std::endl; - int range = (gen.max)()-(gen.min)()+1; - std::vector bucket(range); - for(int j = 0; j < iter; j++) { - int result = gen(); - if(result < (gen.min)() || result > (gen.max)()) - std::cerr << " ... delivers " << result << std::endl; - else - bucket[result-(gen.min)()]++; - } - int sum = 0; - // use a different variable name "k", because MSVC has broken "for" scoping - for(int k = 0; k < range; k++) - sum += bucket[k]; - double avg = static_cast(sum)/range; - double threshold = 2*avg/std::sqrt(static_cast(iter)); - for(int i = 0; i < range; i++) { - if(std::fabs(bucket[i] - avg) > threshold) { - // 95% confidence interval - std::cout << " ... has bucket[" << i << "] = " << bucket[i] - << " (distance " << (bucket[i] - avg) << ")" - << std::endl; - } - } -} - -template -void test_uniform_int(Generator & gen) -{ - typedef boost::uniform_int int_gen; - - // large range => small range (modulo case) - typedef boost::variate_generator level_one; - - level_one uint12(gen, int_gen(1,2)); - BOOST_TEST((uint12.distribution().min)() == 1); - BOOST_TEST((uint12.distribution().max)() == 2); - check_uniform_int(uint12, 100000); - level_one uint16(gen, int_gen(1,6)); - check_uniform_int(uint16, 100000); - - // test chaining to get all cases in operator() - - // identity map - typedef boost::variate_generator level_two; - level_two uint01(uint12, int_gen(0, 1)); - check_uniform_int(uint01, 100000); - - // small range => larger range - level_two uint05(uint12, int_gen(-3, 2)); - check_uniform_int(uint05, 100000); - - // larger => small range, rejection case - typedef boost::variate_generator level_three; - level_three uint1_4(uint05, int_gen(1, 4)); - check_uniform_int(uint1_4, 100000); -} - -#if defined(BOOST_MSVC) && _MSC_VER <= 1200 - -// These explicit instantiations are necessary, otherwise MSVC does -// not find the inline friends. -// We ease the typing with a suitable preprocessor macro. -#define INSTANT(x) \ -template class boost::uniform_smallint; \ -template class boost::uniform_int; \ -template class boost::uniform_real; \ -template class boost::bernoulli_distribution; \ -template class boost::geometric_distribution; \ -template class boost::triangle_distribution; \ -template class boost::exponential_distribution; \ -template class boost::normal_distribution; \ -template class boost::uniform_on_sphere; \ -template class boost::lognormal_distribution; - -INSTANT(boost::minstd_rand0) -INSTANT(boost::minstd_rand) -INSTANT(boost::ecuyer1988) -INSTANT(boost::kreutzer1986) -INSTANT(boost::hellekalek1995) -INSTANT(boost::mt19937) -INSTANT(boost::mt11213b) - -#undef INSTANT -#endif - -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -// testcase by Mario Rütti -class ruetti_gen -{ -public: - typedef boost::uint64_t result_type; - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::numeric_limits::max)(); } - result_type operator()() { return (max)()-1; } -}; - -void test_overflow_range() -{ - ruetti_gen gen; - boost::variate_generator > - rng(gen, boost::uniform_int<>(0, 10)); - for (int i=0;i<10;i++) - (void) rng(); -} -#else -void test_overflow_range() -{ } -#endif - -int test_main(int, char*[]) -{ - -#if !defined(__INTEL_COMPILER) || !defined(_MSC_VER) || __INTEL_COMPILER > 700 - instantiate_all(); - validate_all(); - boost::mt19937 mt; - test_uniform_int(mt); - - // bug report from Ken Mahler: This used to lead to an endless loop. - typedef boost::uniform_int uint_dist; - boost::minstd_rand mr; - boost::variate_generator r2(mr, - uint_dist(0, 0xffffffff)); - r2(); - r2(); - - // bug report from Fernando Cacciola: This used to lead to an endless loop. - // also from Douglas Gregor - boost::variate_generator > x(mr, boost::uniform_int<>(0, 8361)); - (void) x(); - - // bug report from Alan Stokes and others: this throws an assertion - boost::variate_generator > y(mr, boost::uniform_int<>(1,1)); - std::cout << "uniform_int(1,1) " << y() << ", " << y() << ", " << y() - << std::endl; - - test_overflow_range(); - - return 0; -#else - std::cout << "Intel 7.00 on Win32 loops, so the test is disabled\n"; - return 1; -#endif -} diff --git a/statistic_tests.cpp b/statistic_tests.cpp deleted file mode 100644 index 8e07a45..0000000 --- a/statistic_tests.cpp +++ /dev/null @@ -1,669 +0,0 @@ -/* statistic_tests.cpp file - * - * Copyright Jens Maurer 2000, 2002 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - * Revision history - */ - -/* - * NOTE: This is not part of the official boost submission. It exists - * only as a collection of ideas. - */ - -#include -#include -#include -#include -#include // lgamma is not in namespace std -#include -#include - -#include -#include - -#include "statistic_tests.hpp" -#include "integrate.hpp" - - -namespace boost { -namespace random { - -// Wikramaratna 1989 ACORN -template -class additive_congruential -{ -public: - typedef IntType result_type; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION - static const bool has_fixed_range = true; - static const result_type min_value = 0; - static const result_type max_value = m-1; -#else - enum { - has_fixed_range = true, - min_value = 0, - max_value = m-1 - }; -#endif - template - explicit additive_congruential(InputIterator start) { seed(start); } - template - void seed(InputIterator start) - { - for(int i = 0; i <= k; ++i, ++start) - values[i] = *start; - } - - result_type operator()() - { - for(int i = 1; i <= k; ++i) { - IntType tmp = values[i-1] + values[i]; - if(tmp >= m) - tmp -= m; - values[i] = tmp; - } - return values[k]; - } - result_type validation() const { return val; } -private: - IntType values[k+1]; -}; - - -template -class lagged_fibonacci_int -{ -public: - typedef IntType result_type; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION - static const bool has_fixed_range = true; - static const result_type min_value = 0; - static const result_type max_value = m-1; -#else - enum { - has_fixed_range = true, - min_value = 0, - max_value = m-1 - }; -#endif - explicit lagged_fibonacci_int(IntType start) { seed(start); } - template - explicit lagged_fibonacci_int(Generator & gen) { seed(gen); } - void seed(IntType start) - { - linear_congruential init; - seed(init); - } - template - void seed(Generator & gen) - { - assert(r > s); - for(int i = 0; i < 607; ++i) - values[i] = gen(); - current = 0; - lag = r-s; - } - - result_type operator()() - { - result_type tmp = values[current] + values[lag]; - if(tmp >= m) - tmp -= m; - values[current] = tmp; - ++current; - if(current >= r) - current = 0; - ++lag; - if(lag >= r) - lag = 0; - return tmp; - } - result_type validation() const { return val; } -private: - result_type values[r]; - int current, lag; -}; - -} // namespace random -} // namespace boost - -// distributions from Haertel's dissertation -// (additional parameterizations of the basic templates) -namespace Haertel { - typedef boost::random::linear_congruential LCG_Af2; - typedef boost::random::linear_congruential LCG_Die1; - typedef boost::random::linear_congruential LCG_Fis; - typedef boost::random::linear_congruential LCG_FM; - typedef boost::random::linear_congruential LCG_Hae; - typedef boost::random::linear_congruential LCG_VAX; - typedef boost::random::inversive_congruential NLG_Inv1; - typedef boost::random::inversive_congruential NLG_Inv2; - typedef boost::random::inversive_congruential NLG_Inv4; - typedef boost::random::inversive_congruential NLG_Inv5; - typedef boost::random::additive_congruential MRG_Acorn7; - typedef boost::random::lagged_fibonacci_int MRG_Fib2; - - template - inline void check_validation(Gen & gen, T value, const std::string & name) - { - for(int i = 0; i < 100000-1; ++i) - gen(); - if(value != gen()) - std::cout << name << ": validation failed" << std::endl; - } - - // we have validation after 100000 steps with Haertel's generators - template - void validate(T value, const std::string & name) - { - Gen gen(1234567); - check_validation(gen, value, name); - } - - void validate_all() - { - validate(183269031u, "LCG_Af2"); - validate(522319944u, "LCG_Die1"); - validate(-2065162233u, "LCG_Fis"); - validate(581815473u, "LCG_FM"); - validate(28931709, "LCG_Hae"); - validate(1508154087u, "LCG_VAX"); - validate(6666884, "NLG_Inv2"); - validate(1521640076, "NLG_Inv4"); - validate(641840839, "NLG_Inv5"); - static const int acorn7_init[] - = { 1234567, 7654321, 246810, 108642, 13579, 97531, 555555 }; - MRG_Acorn7 acorn7(acorn7_init); - check_validation(acorn7, 874294697, "MRG_Acorn7"); - validate(1234567u, "MRG_Fib2"); - } -} // namespace Haertel - - - - -double normal_density(double x) -{ - const double pi = 3.14159265358979323846; - return 1/std::sqrt(2*pi) * std::exp(-x*x/2); -} - -namespace std { -#ifdef _CXXRTCF_H__ - using _CS_swamp::lgamma; -#elif defined __SGI_STL_PORT - using ::lgamma; -#endif -} - - -class chi_square_density : public std::unary_function -{ -public: - chi_square_density(int freedom) - : _exponent( static_cast(freedom)/2-1 ), - _factor(1/(std::pow(2, _exponent+1) * std::exp(lgamma(_exponent+1)))) - { } - - double operator()(double x) - { - return _factor*std::pow(x, _exponent)*std::exp(-x/2); - } -private: - double _exponent, _factor; -}; - -// computes F(x) or F(y) - F(x) -class chi_square_probability : public distribution_function -{ -public: - chi_square_probability(int freedom) : dens(freedom) {} - double operator()(double x) { return operator()(0, x); } - double operator()(double x, double y) - { return trapezoid(dens, x, y, 1000); } -private: - chi_square_density dens; -}; - -class uniform_distribution : public distribution_function -{ -public: - uniform_distribution(double from, double to) : from(from), to(to) - { assert(from < to); } - double operator()(double x) - { - if(x < from) - return 0; - else if(x > to) - return 1; - else - return (x-from)/(to-from); - } - double operator()(double x, double delta) - { return operator()(x+delta) - operator()(x); } -private: - double from, to; -}; - -class test_environment; - -class test_base -{ -protected: - explicit test_base(test_environment & env) : environment(env) { } - void check(double val) const; -private: - test_environment & environment; -}; - -class equidistribution_test : test_base -{ -public: - equidistribution_test(test_environment & env, unsigned int classes, - unsigned int high_classes) - : test_base(env), classes(classes), - test_distrib_chi_square(chi_square_probability(classes-1), high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "equidistribution: " << std::flush; - equidistribution_experiment equi(classes); - uniform_smallint uint_linear(rng, 0, classes-1); - check(run_experiment(test_distrib_chi_square, - experiment_generator(equi, uint_linear, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(equi, uint_linear, n1), 2*n2)); - - std::cout << " 2D: " << std::flush; - equidistribution_2d_experiment equi_2d(classes); - unsigned int root = static_cast(std::sqrt(double(classes))); - assert(root * root == classes); - uniform_smallint uint_square(rng, 0, root-1); - check(run_experiment(test_distrib_chi_square, - experiment_generator(equi_2d, uint_square, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(equi_2d, uint_square, n1), 2*n2)); - std::cout << std::endl; - } -private: - unsigned int classes; - distribution_experiment test_distrib_chi_square; -}; - -class ks_equidistribution_test : test_base -{ -public: - ks_equidistribution_test(test_environment & env, unsigned int classes) - : test_base(env), - test_distrib_chi_square(kolmogorov_smirnov_probability(5000), - classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "KS: " << std::flush; - // generator_reference_t gen_ref(rng); - RNG& gen_ref(rng); - kolmogorov_experiment ks(n1); - uniform_distribution ud((rng.min)(), (rng.max)()); - check(run_experiment(test_distrib_chi_square, - ks_experiment_generator(ks, gen_ref, ud), n2)); - check(run_experiment(test_distrib_chi_square, - ks_experiment_generator(ks, gen_ref, ud), 2*n2)); - } -private: - distribution_experiment test_distrib_chi_square; -}; - -class runs_test : test_base -{ -public: - runs_test(test_environment & env, unsigned int classes, - unsigned int high_classes) - : test_base(env), classes(classes), - test_distrib_chi_square(chi_square_probability(classes-1), high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "runs: up: " << std::flush; - runs_experiment r_up(classes); - // generator_reference_t gen_ref(rng); - RNG& gen_ref(rng); - check(run_experiment(test_distrib_chi_square, - experiment_generator(r_up, gen_ref, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(r_up, gen_ref, n1), 2*n2)); - - std::cout << " down: " << std::flush; - runs_experiment r_down(classes); - check(run_experiment(test_distrib_chi_square, - experiment_generator(r_down, gen_ref, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(r_down, gen_ref, n1), 2*n2)); - - std::cout << std::endl; - } -private: - unsigned int classes; - distribution_experiment test_distrib_chi_square; -}; - -class gap_test : test_base -{ -public: - gap_test(test_environment & env, unsigned int classes, - unsigned int high_classes) - : test_base(env), classes(classes), - test_distrib_chi_square(chi_square_probability(classes-1), high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "gaps: " << std::flush; - gap_experiment gap(classes, 0.2, 0.8); - // generator_reference_t gen_ref(rng); - RNG& gen_ref(rng); - check(run_experiment(test_distrib_chi_square, - experiment_generator(gap, gen_ref, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(gap, gen_ref, n1), 2*n2)); - - std::cout << std::endl; - } -private: - unsigned int classes; - distribution_experiment test_distrib_chi_square; -}; - -class poker_test : test_base -{ -public: - poker_test(test_environment & env, unsigned int classes, - unsigned int high_classes) - : test_base(env), classes(classes), - test_distrib_chi_square(chi_square_probability(classes-1), high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "poker: " << std::flush; - poker_experiment poker(8, classes); - uniform_smallint usmall(rng, 0, 7); - check(run_experiment(test_distrib_chi_square, - experiment_generator(poker, usmall, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(poker, usmall, n1), 2*n2)); - std::cout << std::endl; - } -private: - unsigned int classes; - distribution_experiment test_distrib_chi_square; -}; - -class coupon_collector_test : test_base -{ -public: - coupon_collector_test(test_environment & env, unsigned int classes, - unsigned int high_classes) - : test_base(env), classes(classes), - test_distrib_chi_square(chi_square_probability(classes-1), high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "coupon collector: " << std::flush; - coupon_collector_experiment coupon(5, classes); - - uniform_smallint usmall(rng, 0, 4); - check(run_experiment(test_distrib_chi_square, - experiment_generator(coupon, usmall, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(coupon, usmall, n1), 2*n2)); - std::cout << std::endl; - } -private: - unsigned int classes; - distribution_experiment test_distrib_chi_square; -}; - -class permutation_test : test_base -{ -public: - permutation_test(test_environment & env, unsigned int classes, - unsigned int high_classes) - : test_base(env), classes(classes), - test_distrib_chi_square(chi_square_probability(fac(classes)-1), - high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "permutation: " << std::flush; - permutation_experiment perm(classes); - - // generator_reference_t gen_ref(rng); - RNG& gen_ref(rng); - check(run_experiment(test_distrib_chi_square, - experiment_generator(perm, gen_ref, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(perm, gen_ref, n1), 2*n2)); - std::cout << std::endl; - } -private: - unsigned int classes; - distribution_experiment test_distrib_chi_square; -}; - -class maximum_test : test_base -{ -public: - maximum_test(test_environment & env, unsigned int high_classes) - : test_base(env), - test_distrib_chi_square(kolmogorov_smirnov_probability(1000), - high_classes) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "maximum-of-t: " << std::flush; - maximum_experiment mx(rng, n1, 5); - check(run_experiment(test_distrib_chi_square, mx, n2)); - check(run_experiment(test_distrib_chi_square, mx, 2*n2)); - std::cout << std::endl; - } -private: - distribution_experiment test_distrib_chi_square; -}; - -class birthday_test : test_base -{ -public: - birthday_test(test_environment & env) - : test_base(env) - { } - - template - void run(RNG & rng, int n1, int n2) - { - using namespace boost; - std::cout << "birthday spacing: " << std::flush; - uniform_int uni(rng, 0, (1<<25)-1); - birthday_spacing_experiment bsp(4, 512, (1<<25)); - std::cout << run_experiment(bsp, uni, n1); -#if 0 - check(run_experiment(test_distrib_chi_square, - experiment_generator(perm, gen_ref, n1), n2)); - check(run_experiment(test_distrib_chi_square, - experiment_generator(perm, gen_ref, n1), 2*n2)); -#endif - std::cout << std::endl; - } - - -}; - -class test_environment -{ -public: - static const int classes = 20; - explicit test_environment(double confid) - : confidence(confid), - confidence_chi_square_quantil(quantil(chi_square_density(classes-1), 0, confidence, 1e-4)), - test_distrib_chi_square6(chi_square_probability(7-1), classes), - ksequi_test(*this, classes), - equi_test(*this, 100, classes), - rns_test(*this, 7, classes), - gp_test(*this, 7, classes), - pk_test(*this, 5, classes), - cpn_test(*this, 15, classes), - perm_test(*this, 5, classes), - max_test(*this, classes), - bday_test(*this) - { - std::cout << "Confidence level: " << confid - << "; 1-alpha = " << (1-confid) - << "; chi_square(" << (classes-1) - << ", " << confidence_chi_square_quantil - << ") = " - << chi_square_probability(classes-1)(0, confidence_chi_square_quantil) - << std::endl; - } - - bool check_confidence(double val, double chi_square_conf) const - { - std::cout << val; - bool result = (val <= chi_square_conf); - if(!result) { - std::cout << "* ["; - double prob = (val > 10*chi_square_conf ? 1 : - chi_square_probability(classes-1)(0, val)); - std::cout << (1-prob) << "]"; - } - std::cout << " " << std::flush; - return result; - } - - bool check(double chi_square_value) const - { - return check_confidence(chi_square_value, confidence_chi_square_quantil); - } - - template - void run_test(const std::string & name) - { - using namespace boost; - - std::cout << "Running tests on " << name << std::endl; - - RNG rng(1234567); - typedef boost::uniform_01 UGen; - -#if 1 - ksequi_test.run(rng, 5000, 250); - equi_test.run(rng, 5000, 250); - rns_test.run(rng, 100000, 250); - gp_test.run(rng, 10000, 250); - pk_test.run(rng, 5000, 250); - cpn_test.run(rng, 500, 250); - perm_test.run(rng, 1200, 250); - max_test.run(rng, 1000, 250); -#endif - bday_test.run(rng, 1000, 150); - - std::cout << std::endl; - } - -private: - double confidence; - double confidence_chi_square_quantil; - distribution_experiment test_distrib_chi_square6; - ks_equidistribution_test ksequi_test; - equidistribution_test equi_test; - runs_test rns_test; - gap_test gp_test; - poker_test pk_test; - coupon_collector_test cpn_test; - permutation_test perm_test; - maximum_test max_test; - birthday_test bday_test; -}; - -void test_base::check(double val) const -{ - environment.check(val); -} - -void print_ks_table() -{ - std::cout.setf(std::ios::fixed); - std::cout.precision(5); - static const double all_p[] = { 0.01, 0.05, 0.25, 0.5, 0.75, 0.95, 0.99 }; - for(int n = 0; n <= 10000; (n < 55 ? ++n : n *= 10)) { - std::cout << std::setw(4) << n << " "; - for(unsigned int i = 0; i < sizeof(all_p)/sizeof(all_p[0]); ++i) { - std::cout << std::setw(8) - << (n == 0 ? all_p[i] : - invert_monotone_inc(kolmogorov_smirnov_probability(n), all_p[i], 0, 10)) - << " "; - } - std::cout << std::endl; - } -} - -int main() -{ - // Haertel::validate_all(); - test_environment env(0.99); - env.run_test("minstd_rand"); - env.run_test("mt19937"); - env.run_test("LCG_Af2"); - env.run_test("LCG_Die1"); - env.run_test("LCG_Fis"); - env.run_test("LCG_FM"); - env.run_test("LCG_Hae"); - env.run_test("LCG_VAX"); - env.run_test("NLG_Inv1"); - env.run_test("NLG_Inv2"); - env.run_test("NLG_Inv4"); - env.run_test("NLG_Inv5"); -} diff --git a/statistic_tests.hpp b/statistic_tests.hpp deleted file mode 100644 index a7871cb..0000000 --- a/statistic_tests.hpp +++ /dev/null @@ -1,643 +0,0 @@ -/* statistic_tests.hpp header file - * - * Copyright Jens Maurer 2000 - * Permission to use, copy, modify, sell, and distribute this software - * is hereby granted without fee provided that the above copyright notice - * appears in all copies and that both that copyright notice and this - * permission notice appear in supporting documentation, - * - * Jens Maurer makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * $Id$ - * - */ - -#ifndef STATISTIC_TESTS_HPP -#define STATISTIC_TESTS_HPP - -#include -#include -#include -#include -#include -#include - -#include -#include - - -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 -namespace std -{ - inline double pow(double a, double b) { return ::pow(a,b); } - inline double ceil(double x) { return ::ceil(x); } -} // namespace std -#endif - - -template -inline T fac(int k) -{ - T result = 1; - for(T i = 2; i <= k; ++i) - result *= i; - return result; -} - -template -T binomial(int n, int k) -{ - if(k < n/2) - k = n-k; - T result = 1; - for(int i = k+1; i<= n; ++i) - result *= i; - return result / fac(n-k); -} - -template -T stirling2(int n, int m) -{ - T sum = 0; - for(int k = 0; k <= m; ++k) - sum += binomial(m, k) * std::pow(double(k), n) * - ( (m-k)%2 == 0 ? 1 : -1); - return sum / fac(m); -} - -/* - * Experiments which create an empirical distribution in classes, - * suitable for the chi-square test. - */ -// std::floor(gen() * classes) - -class experiment_base -{ -public: - experiment_base(int cls) : _classes(cls) { } - unsigned int classes() const { return _classes; } -protected: - unsigned int _classes; -}; - -class equidistribution_experiment : public experiment_base -{ -public: - explicit equidistribution_experiment(unsigned int classes) - : experiment_base(classes) { } - - template - void run(NumberGenerator f, Counter & count, int n) const - { - assert((f.min)() == 0 && - static_cast((f.max)()) == classes()-1); - for(int i = 0; i < n; ++i) - count(f()); - } - double probability(int i) const { return 1.0/classes(); } -}; - -// two-dimensional equidistribution experiment -class equidistribution_2d_experiment : public equidistribution_experiment -{ -public: - explicit equidistribution_2d_experiment(unsigned int classes) - : equidistribution_experiment(classes) { } - - template - void run(NumberGenerator f, Counter & count, int n) const - { - unsigned int range = (f.max)()+1; - assert((f.min)() == 0 && range*range == classes()); - for(int i = 0; i < n; ++i) { - int y1 = f(); - int y2 = f(); - count(y1 + range * y2); - } - } -}; - -// distribution experiment: assume a probability density and -// count events so that an equidistribution results. -class distribution_experiment : public equidistribution_experiment -{ -public: - template - distribution_experiment(UnaryFunction probability , unsigned int classes) - : equidistribution_experiment(classes), limit(classes) - { - for(unsigned int i = 0; i < classes-1; ++i) - limit[i] = invert_monotone_inc(probability, (i+1)*0.05, 0, 1000); - limit[classes-1] = std::numeric_limits::infinity(); - if(limit[classes-1] < (std::numeric_limits::max)()) - limit[classes-1] = (std::numeric_limits::max)(); -#if 0 - std::cout << __PRETTY_FUNCTION__ << ": "; - for(unsigned int i = 0; i < classes; ++i) - std::cout << limit[i] << " "; - std::cout << std::endl; -#endif - } - - template - void run(NumberGenerator f, Counter & count, int n) const - { - for(int i = 0; i < n; ++i) { - limits_type::const_iterator it = - std::lower_bound(limit.begin(), limit.end(), f()); - count(it-limit.begin()); - } - } -private: - typedef std::vector limits_type; - limits_type limit; -}; - -// runs-up/runs-down experiment -template -class runs_experiment : public experiment_base -{ -public: - explicit runs_experiment(unsigned int classes) : experiment_base(classes) { } - - template - void run(UniformRandomNumberGenerator f, Counter & count, int n) const - { - typedef typename UniformRandomNumberGenerator::result_type result_type; - result_type init = (up ? (f.min)() : (f.max)()); - result_type previous = init; - unsigned int length = 0; - for(int i = 0; i < n; ++i) { - result_type val = f(); - if(up ? previous <= val : previous >= val) { - previous = val; - ++length; - } else { - count((std::min)(length, classes())-1); - length = 0; - previous = init; - // don't use this value, so that runs are independent - } - } - } - double probability(unsigned int r) const - { - if(r == classes()-1) - return 1.0/fac(classes()); - else - return static_cast(r+1)/fac(r+2); - } -}; - -// gap length experiment -class gap_experiment : public experiment_base -{ -public: - gap_experiment(unsigned int classes, double alpha, double beta) - : experiment_base(classes), alpha(alpha), beta(beta) { } - - template - void run(UniformRandomNumberGenerator f, Counter & count, int n) const - { - typedef typename UniformRandomNumberGenerator::result_type result_type; - double range = (f.max)() - (f.min)() + 1.0; - result_type low = static_cast(alpha * range); - result_type high = static_cast(beta * range); - unsigned int length = 0; - for(int i = 0; i < n; ) { - result_type value = f() - (f.min)(); - if(value < low || value > high) - ++length; - else { - count((std::min)(length, classes()-1)); - length = 0; - ++i; - } - } - } - double probability(unsigned int r) const - { - double p = beta-alpha; - if(r == classes()-1) - return std::pow(1-p, static_cast(r)); - else - return p * std::pow(1-p, static_cast(r)); - } -private: - double alpha, beta; -}; - -// poker experiment -class poker_experiment : public experiment_base -{ -public: - poker_experiment(unsigned int d, unsigned int k) - : experiment_base(k), range(d) - { - assert(range > 1); - } - - template - void run(UniformRandomNumberGenerator f, Counter & count, int n) const - { - typedef typename UniformRandomNumberGenerator::result_type result_type; - assert(std::numeric_limits::is_integer); - assert((f.min)() == 0); - assert((f.max)() == static_cast(range-1)); - std::vector v(classes()); - for(int i = 0; i < n; ++i) { - for(unsigned int j = 0; j < classes(); ++j) - v[j] = f(); - std::sort(v.begin(), v.end()); - result_type prev = v[0]; - int r = 1; // count different values in v - for(unsigned int i = 1; i < classes(); ++i) { - if(prev != v[i]) { - prev = v[i]; - ++r; - } - } - count(r-1); - } - } - - double probability(unsigned int r) const - { - ++r; // transform to 1 <= r <= 5 - double result = range; - for(unsigned int i = 1; i < r; ++i) - result *= range-i; - return result / std::pow(range, static_cast(classes())) * - stirling2(classes(), r); - } -private: - unsigned int range; -}; - -// coupon collector experiment -class coupon_collector_experiment : public experiment_base -{ -public: - coupon_collector_experiment(unsigned int d, unsigned int cls) - : experiment_base(cls), d(d) - { - assert(d > 1); - } - - template - void run(UniformRandomNumberGenerator f, Counter & count, int n) const - { - typedef typename UniformRandomNumberGenerator::result_type result_type; - assert(std::numeric_limits::is_integer); - assert((f.min)() == 0); - assert((f.max)() == static_cast(d-1)); - std::vector occurs(d); - for(int i = 0; i < n; ++i) { - occurs.assign(d, false); - unsigned int r = 0; // length of current sequence - int q = 0; // number of non-duplicates in current set - for(;;) { - result_type val = f(); - ++r; - if(!occurs[val]) { // new set element - occurs[val] = true; - ++q; - if(q == d) - break; // one complete set - } - } - count((std::min)(r-d, classes()-1)); - } - } - double probability(unsigned int r) const - { - if(r == classes()-1) - return 1-fac(d)/std::pow(d, static_cast(d+classes()-2))* - stirling2(d+classes()-2, d); - else - return fac(d)/std::pow(d, static_cast(d+r)) * - stirling2(d+r-1, d-1); - } -private: - int d; -}; - -// permutation test -class permutation_experiment : public equidistribution_experiment -{ -public: - permutation_experiment(unsigned int t) - : equidistribution_experiment(fac(t)), t(t) - { - assert(t > 1); - } - - template - void run(UniformRandomNumberGenerator f, Counter & count, int n) const - { - typedef typename UniformRandomNumberGenerator::result_type result_type; - std::vector v(t); - for(int i = 0; i < n; ++i) { - std::generate_n(v.begin(), t, f); - int x = 0; - for(int r = t-1; r > 0; r--) { - typename std::vector::iterator it = - std::max_element(v.begin(), v.begin()+r+1); - x = (r+1)*x + (it-v.begin()); - std::iter_swap(it, v.begin()+r); - } - count(x); - } - } -private: - int t; -}; - -// birthday spacing experiment test -class birthday_spacing_experiment : public experiment_base -{ -public: - birthday_spacing_experiment(unsigned int d, int n, int m) - : experiment_base(d), n(n), m(m) - { - } - - template - void run(UniformRandomNumberGenerator f, Counter & count, int n_total) const - { - typedef typename UniformRandomNumberGenerator::result_type result_type; - assert(std::numeric_limits::is_integer); - assert((f.min)() == 0); - assert((f.max)() == static_cast(m-1)); - - for(int j = 0; j < n_total; j++) { - std::vector v(n); - std::generate_n(v.begin(), n, f); - std::sort(v.begin(), v.end()); - std::vector spacing(n); - for(int i = 0; i < n-1; i++) - spacing[i] = v[i+1]-v[i]; - spacing[n-1] = v[0] + m - v[n-1]; - std::sort(spacing.begin(), spacing.end()); - unsigned int k = 0; - for(int i = 0; i < n-1; ++i) { - if(spacing[i] == spacing[i+1]) - ++k; - } - count((std::min)(k, classes()-1)); - } - } - - double probability(unsigned int r) const - { - assert(classes() == 4); - assert(m == (1<<25)); - assert(n == 512); - static const double prob[] = { 0.368801577, 0.369035243, 0.183471182, - 0.078691997 }; - return prob[r]; - } -private: - int n, m; -}; -/* - * Misc. helper functions. - */ - -template -struct distribution_function -{ - typedef Float result_type; - typedef Float argument_type; - typedef Float first_argument_type; - typedef Float second_argument_type; -}; - -// computes P(K_n <= t) or P(t1 <= K_n <= t2). See Knuth, 3.3.1 -class kolmogorov_smirnov_probability : public distribution_function -{ -public: - kolmogorov_smirnov_probability(int n) - : approx(n > 50), n(n), sqrt_n(std::sqrt(double(n))) - { - if(!approx) - n_n = std::pow(static_cast(n), n); - } - - double operator()(double t) const - { - if(approx) { - return 1-std::exp(-2*t*t)*(1-2.0/3.0*t/sqrt_n); - } else { - t *= sqrt_n; - double sum = 0; - for(int k = static_cast(std::ceil(t)); k <= n; k++) - sum += binomial(n, k) * std::pow(k-t, k) * - std::pow(t+n-k, n-k-1); - return 1 - t/n_n * sum; - } - } - double operator()(double t1, double t2) const - { return operator()(t2) - operator()(t1); } - -private: - bool approx; - int n; - double sqrt_n; - double n_n; -}; - -/* - * Experiments for generators with continuous distribution functions - */ -class kolmogorov_experiment -{ -public: - kolmogorov_experiment(int n) : n(n), ksp(n) { } - template - double run(NumberGenerator gen, Distribution distrib) const - { - const int m = n; - typedef std::vector saved_temp; - saved_temp a(m,1.0), b(m,0); - std::vector c(m,0); - for(int i = 0; i < n; ++i) { - double val = gen(); - double y = distrib(val); - int k = static_cast(std::floor(m*y)); - if(k >= m) - --k; // should not happen - a[k] = (std::min)(a[k], y); - b[k] = (std::max)(b[k], y); - ++c[k]; - } - double kplus = 0, kminus = 0; - int j = 0; - for(int k = 0; k < m; ++k) { - if(c[k] > 0) { - kminus = (std::max)(kminus, a[k]-j/static_cast(n)); - j += c[k]; - kplus = (std::max)(kplus, j/static_cast(n) - b[k]); - } - } - kplus *= std::sqrt(double(n)); - kminus *= std::sqrt(double(n)); - // std::cout << "k+ " << kplus << " k- " << kminus << std::endl; - return kplus; - } - double probability(double x) const - { - return ksp(x); - } -private: - int n; - kolmogorov_smirnov_probability ksp; -}; - -// maximum-of-t test (KS-based) -template -class maximum_experiment -{ -public: - typedef UniformRandomNumberGenerator base_type; - maximum_experiment(base_type & f, int n, int t) : f(f), ke(n), t(t) - { } - - double operator()() const - { - double res = ke.run(generator(f, t), - std::bind2nd(std::ptr_fun(static_cast(&std::pow)), t)); - return res; - } - -private: - struct generator { - generator(base_type & f, int t) : f(f), t(t) { } - double operator()() - { - double mx = f(); - for(int i = 1; i < t; ++i) - mx = (std::max)(mx, f()); - return mx; - } - private: - boost::uniform_01 f; - int t; - }; - base_type & f; - kolmogorov_experiment ke; - int t; -}; - -// compute a chi-square value for the distribution approximation error -template -typename UnaryFunction::result_type -chi_square_value(ForwardIterator first, ForwardIterator last, - UnaryFunction probability) -{ - typedef std::iterator_traits iter_traits; - typedef typename iter_traits::value_type counter_type; - typedef typename UnaryFunction::result_type result_type; - unsigned int classes = std::distance(first, last); - result_type sum = 0; - counter_type n = 0; - for(unsigned int i = 0; i < classes; ++first, ++i) { - counter_type count = *first; - n += count; - sum += (count/probability(i)) * count; // avoid overflow - } -#if 0 - for(unsigned int i = 0; i < classes; ++i) { - // std::cout << (n*probability(i)) << " "; - if(n * probability(i) < 5) - std::cerr << "Not enough test runs for slot " << i - << " p=" << probability(i) << ", n=" << n - << std::endl; - } -#endif - // std::cout << std::endl; - // throw std::invalid_argument("not enough test runs"); - - return sum/n - n; -} -template -class generic_counter -{ -public: - explicit generic_counter(unsigned int classes) : container(classes, 0) { } - void operator()(int i) - { - assert(i >= 0); - assert(static_cast(i) < container.size()); - ++container[i]; - } - typename RandomAccessContainer::const_iterator begin() const - { return container.begin(); } - typename RandomAccessContainer::const_iterator end() const - { return container.end(); } - -private: - RandomAccessContainer container; -}; - -// chi_square test -template -double run_experiment(const Experiment & experiment, Generator gen, int n) -{ - generic_counter > v(experiment.classes()); - experiment.run(gen, v, n); - return chi_square_value(v.begin(), v.end(), - std::bind1st(std::mem_fun_ref(&Experiment::probability), - experiment)); -} - -// number generator with experiment results (for nesting) -template -class experiment_generator_t -{ -public: - experiment_generator_t(const Experiment & exper, Generator & gen, int n) - : experiment(exper), generator(gen), n(n) { } - double operator()() { return run_experiment(experiment, generator, n); } -private: - const Experiment & experiment; - Generator & generator; - int n; -}; - -template -experiment_generator_t -experiment_generator(const Experiment & e, Generator & gen, int n) -{ - return experiment_generator_t(e, gen, n); -} - - -template -class ks_experiment_generator_t -{ -public: - ks_experiment_generator_t(const Experiment & exper, Generator & gen, - const Distribution & distrib) - : experiment(exper), generator(gen), distribution(distrib) { } - double operator()() { return experiment.run(generator, distribution); } -private: - const Experiment & experiment; - Generator & generator; - Distribution distribution; -}; - -template -ks_experiment_generator_t -ks_experiment_generator(const Experiment & e, Generator & gen, - const Distribution & distrib) -{ - return ks_experiment_generator_t - (e, gen, distrib); -} - - -#endif /* STATISTIC_TESTS_HPP */ - diff --git a/test/Jamfile b/test/Jamfile deleted file mode 100644 index 963f0cc..0000000 --- a/test/Jamfile +++ /dev/null @@ -1,25 +0,0 @@ -# Boost Random Library test Jamfile - -subproject libs/random/test ; - -# bring in rules for testing -import testing ; - -# Make tests run by default. -DEPENDS all : test ; - -{ - # look in BOOST_ROOT for sources first, just in this Jamfile - local SEARCH_SOURCE = $(BOOST_ROOT) $(SEARCH_SOURCE) ; - - test-suite "random" - : - [ run libs/random/random_test.cpp ] - [ run libs/random/random_demo.cpp ] -# [ run libs/random/nondet_random_speed.cpp ] -# [ run libs/random/random_device.cpp ] -# [ run libs/random/random_speed.cpp ] -# [ run libs/random/statistic_tests.cpp ] - ; -} - diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 deleted file mode 100644 index d114fbd..0000000 --- a/test/Jamfile.v2 +++ /dev/null @@ -1,20 +0,0 @@ -# Boost Random Library test Jamfile - -# bring in rules for testing -import testing ; - -project - : source-location $(BOOST_ROOT) - ; -{ - test-suite "random" - : - [ run libs/random/random_test.cpp ] - [ run libs/random/random_demo.cpp ] -# [ run libs/random/nondet_random_speed.cpp ] -# [ run libs/random/random_device.cpp ] -# [ run libs/random/random_speed.cpp ] -# [ run libs/random/statistic_tests.cpp ] - ; -} - diff --git a/wg21-proposal.html b/wg21-proposal.html deleted file mode 100644 index 9b50caf..0000000 --- a/wg21-proposal.html +++ /dev/null @@ -1,3518 +0,0 @@ - - - A Proposal to Add an Extensible Random Number Facility to the Standard Library - - - - - - -Jens Maurer <Jens.Maurer@gmx.net> -
-2002-11-10 -
-Document N1398=02-0056 -

-$Id: proposal.html,v 1.44 2002/11/10 20:42:15 jmaurer Exp $ - - -

A Proposal to Add an Extensible Random Number Facility to the -Standard Library (N1398)

- -
-Any one who considers arithmetical methods of producing random digits -is, of course, in a state of sin. -
-

-John von Neumann, 1951 -

- -

Revision history

- -
    -
  • 2002-11-10: Publication in the Post-Santa Cruz mailing. -
  • The seed(first, last) interface now needs "unsigned -long" values. -
  • Introduce "variate_generator", adjust distribution interface -accordingly. -
  • Add "add-on packages" discussion. -
  • All distribution parameters must be defaulted. -
  • Add "target audience" subsection to "motivation" section. -
  • Add discussion of manager class. -
  • Engines are independent of distributions, thus consider respective -lifetimes. -
  • Add "sharing of engines" as a major requirement. -
  • Add some open issues. -
  • 2002-10-11: First publication on the C++ committee's library reflector. -
- - -

I. Motivation

- -
Why is this important? What kinds of problems does it -address, and what kinds of programmers, is it intended to support? Is -it based on existing practice?
- -Computers are deterministic machines by design: equal input data -results in equal output, given the same internal state. Sometimes, -applications require seemingly non-deterministic behaviour, usually -provided by generating random numbers. Such applications include: -
    -
  • numerics (simulation, Monte-Carlo integration) -
  • games (shuffling card decks, non-deterministic enemy behavior) -
  • testing (generation of test input data for good coverage) -
  • security (generation of cryptographic keys) -
-

- -Programmers in all of the above areas have to find ways to generate -random numbers. However, the difficulty to find generators that are -both efficient and have good quality is often underestimated, and so -ad-hoc implementations often fail to meet either or both of these -goals. -

- -The C++ standard library includes std::rand, inherited -from the C standard library, as the only facility to generate -pseudo-random numbers. It is underspecified, because the generation -function is not defined, and indeed early C standard library -implementations provided surprisingly bad generators. Furthermore, -the interface relies on global state, making it difficult or -inefficient to provide for correct operation for simultaneous -invocations in multi-threaded applications. -

- -There is a lot of existing practice in this area. A multitude of -libraries, usually implemented in C or Fortran, is available from the -scientific community. Some implement just one random number -engine, others seek to provide a full framework. I know of no -comprehensive C++ framework for generating random numbers that adheres -to the design principles put forth in section III. -

- -Random number generators are appropriate for this TR because they fall -into one of the domains (numerics) identified in N1314 as a target for -the TR. - - -

Target Audience

- -There are several different kinds of programmers that are assumed to use -the facilities provided in this proposal. - -
    -
  • programmers that provide additional engines -
  • programmers that provide additional distributions -
  • programmers that provide generic add-on packages -
  • programmers that need random numbers -
- -This proposal specifies an infrastructure so that the needs of all -four groups are met. The first two groups benefit from a modular -design so that they can plug in their contributions. Providing add-on -packages benefits from a design that suits to generic programming -needs. Finally, users in need of random numbers benefit from an -interface to the package that is easy to use. - - -

II. Impact On the Standard

- -
What does it depend on, and what depends on it? Is it -a pure extension, or does it require changes to standard components? -Does it require core language changes?
- -This proposal is a pure library extension. It does not require -changes to any standard classes or functions. It does not require -changes to any of the standard requirement tables. It does not -require any changes in the core language, and it has been implemented -in standard C++ as per ISO 14882:1998. -

- -The ISO C99 extension that specify integral types having a given -minimum or exact bitwidth (e.g. int32_t) aids in -implementing this proposal, however these types (or the equivalent -thereof under another name) can be defined with template -metaprogramming in standard C++, so these are not strictly necessary. -

- -In case the ISO C99 extensions become part of the TR, section IV should -be reviewed whether some requirements could be reformulated with the -ISO C99 extensions. -

- -In case a standard reference-counted smart pointer becomes part of -the TR, section IV should be reviewed and instances of the smart -pointer be added to the acceptable template parameters for a -variate_generator. - - -

III. Design Decisions

- -
Why did you choose the specific design that you did? -What alternatives did you consider, and what are the tradeoffs? What -are the consequences of your choice, for users and implementors? What -decisions are left up to implementors? If there are any similar -libraries in use, how do their design decisions compare to yours? -
- - -The design decisions are compared to those in the following libraries: -
    -
  • CLHEP (original at -http://wwwinfo.cern.ch/asd/lhc++/clhep/index.html, modifications from -FermiLab at (anonymous CVS) -:pserver:anonymous@zoomcvs.fnal.gov:/usr/people/cvsuser/repository) -
  • - -
  • crng 1.1: Random-number generators (RNGs) implemented as Python -extension types coded in C (at http://www.sbc.su.se/~per/crng/) -
  • - -
  • Swarm 2.1.1 (multi-agent simulation of complex systems), random -number package, using a Smalltalk-like programming language (at -http://www.santafe.edu/projects/swarm/swarmdocs/set/swarm.random.sgml.reference.html) -
  • - -
  • GNU Scientific Library: general scientific computing library -implemented in C, comprehensive coverage of random number engines and -distributions (at http://sources.redhat.com/gsl) - -
- - -The choice of engines and distributions is also contrasted against the -following literature: - -
    -
  • Donald E. Knuth, "The Art of Computer Programming Vol. 2" -
  • - -
  • William H. Press et al., "Numerical Recipes in C" -
  • - -
- - -

A. Overview on Requirements

- -Here is a short overview on the requirements for the random number -framework. - -
    -
  • allows users to choose in speed / size / quality trade-offs -
  • has a tight enough specification to get reliable cross-platform -results -
  • allows storage of state on non-volatile media (e.g., in a disk -file) to resume computation later -
  • does not impede sequence "jump-ahead" for parallel computation -
  • provides a variety of base engines, not just one -
  • allows the user to write its own base engines and use it with the -library-provided distributions -
  • provides the most popular distributions -
  • allows the user to write its own distributions and use it with the -library-provided engines -
  • allows sharing of engines by several distributions -
  • does not prevent implementations with utmost efficiency -
  • provides both pseudo-random number engines (for simulations etc.) -and "true" non-deterministic random numbers (for cryptography) -
- -All of the requirements are revisited in detail in the following -sections. - - -

B. Pseudo-Random vs. Non-Deterministic Random Numbers

- -This section tries to avoid philosophical discussions about randomness -as much as possible, a certain amount of intuition is assumed. -

- -In this proposal, a pseudo-random number engine is defined as -an initial internal state x(0), a function f that -moves from one internal state to the next x(i+1) := f(x(i)), and an -output function o that produces the output o(x(i)) of the generator. -This is an entirely deterministic process, it is determined by the -initial state x(0) and functions f and o only. -The initial state x(0) is determined from a seed. Apparent randomness -is achieved only because the user has limited perception. -

- -A non-deterministic random-number engine provides a -sequence of random numbers x(i) that cannot be foreseen. Examples are -certain quantum-level physics experiments, measuring the time -difference between radioactive decay of individual atoms or noise of a -Zehner diode. Relatively unforeseeable random sources are also (the -low bits of) timing between key touches, mouse movements, Ethernet -packet arrivals, etc. An estimate for the amount of -unforeseeability is the entropy, a concept from information theory. -Completely foreseeable sequences (e.g., from pseudo-random number -engines) have entropy 0, if all bits are unforeseeable, the entropy is -equal to the number of bits in each number. -

- -Pseudo-random number engines are usually much faster than -non-deterministic random-number engines, because the latter require -I/O to query some randomness device outside of the computer. However, -there is a common interface feature subset of both pseudo-random and -non-deterministic random-number engines. For example, a -non-deterministic random-number engine could be employed to produce -random numbers with normal distribution; I believe this to be an -unlikely scenario in practice. -

- -Other libraries, including those mentioned above, only provide -either pseudo-random numbers, suitable for simulations and games, or -non-deterministic random numbers, suitable for cryptographic -applications. - - - -

C. Separation of Engines and Distributions

- -Random-number generation is usually conceptually separated into -random-number engines that produce uniformly distributed -random numbers between a given minimum and maximum and -random-number distributions that retrieve uniformly -distributed random numbers from some engine and produce numbers -according to some distribution (e.g., Gaussian normal or Bernoulli -distribution). -Returning to the formalism from section A, the former can be identified -with the function f and the latter with the output function o. -

- -This proposal honours this conceptual separation, and provides a class -template to merge an arbitrary engine with an arbitrary distribution -on top. To this end, this proposal sets up requirements for -engines so that each of them can be used to provide uniformly -distributed random numbers for any of the distributions. The -resulting freedom of combination allows for the utmost re-use. -

- -Engines have usually been analyzed with all mathematical and empirical -tools currently available. Nonetheless, those tools show the absence -of a particular weakness only, and are not exhaustive. Albeit -unlikely, a new kind of test (for example, a use of random numbers in -a new kind of simulation or game) could show serious weaknesses in -some engines that were not known before. -

- -This proposal attempts to specify the engines precisely; two different -implementations, with the same seed, should return the same output -sequence. This forces implementations to use the well-researched -engines specified hereinafter, and users can have confidence in their -quality and the limits thereof. -

- -On the other hand, the specifications for the distributions only -define the statistical result, not the precise algorithm to use. This -is different from engines, because for distribution algorithms, -rigorous proofs of their correctness are available, usually under the -precondition that the input random numbers are (truely) uniformly -distributed. For example, there are at least a handful of algorithms -known to produce normally distributed random numbers from uniformly -distributed ones. Which one of these is most efficient depends on at -least the relative execution speeds for various transcendental -functions, cache and branch prediction behaviour of the CPU, and -desired memory use. This proposal therefore leaves the choice of the -algorithm to the implementation. It follows that output sequences for -the distributions will not be identical across implementations. It is -expected that implementations will carefully choose the algorithms for -distributions up front, since it is certainly surprising to customers -if some distribution produces different numbers from one -implementation version to the next. -

- -Other libraries usually provide the same differentiation between -engines and distributions. Libraries rarely have a wrapper around -both engine and distribution, but it turns out that this can hide some -complexities from the authors of distributions, since some facitilies -need to be provided only once. A previous version of this proposal -had distributions directly exposed to the user, and the distribution -type dependent on the engine type. In various discussions, this was -considered as too much coupling. -

- -Since other libraries do not aim to provide a portable specification -framework, engines are sometimes only described qualitatively without -giving the exact parameterization. Also, distributions are given as -specific functions or classes, so the quality-of-implementation -question which distribution algorithm to employ does not need to be -addressed. - - -

D. Templates vs. Virtual Functions

- -The layering sketched in the previous subsection can be implemented by -either a template mechanism or by using virtual functions in a class -hierarchy. This proposal uses templates. Template parameters are -usually some base type and values denoting fixed parameters for the -functions f and o, e.g. a word size or modulus. -

- -For virtual functions in a class hierarchy, the core language requires -a (nearly) exact type match for a function in a derived classes -overriding a function in a base class. This seems to be unnecessarily -restrictive, because engines can sometimes benefit from using -different integral base types. Also, with -current compiler technology, virtual functions prevent inlining when a -pointer to the base class is used to call a virtual function that is -overridden in some derived class. In particular with applications -such as simulations that sometimes use millions of pseudo-random -numbers per second, losing significant amounts of performance due to -missed inlining opportunities appears to not be acceptable. -

- -The CLHEP library bases all its engines on the abstract base class -HepRandomEngine. Specific engines derive from this class -and override its pure virtual functions. Similarly, all -distributions are based on the base class HepRandom. -Specific distributions derive from this class, override operator(), -and provide a number of specific non-virtual functions. -

- -The GNU Scientific Library, while coded in C, adheres to the -principles of object-structuring; all engines can be used with any of -the distributions. The technical implementation is by mechanisms -similar to virtual functions. - - -

E. Parameterization and Initialization for Engines

- -Engines usually have a "base" type which is used to store its internal -state. Also, they usually have a choice of parameters. For example, -a linear congruential engine is defined by x(i+1) = (a*x(i)+c) mod m, -so f(x) = (a*x+c) mod m; the base type is "int" and parameters are a, -c, and m. Finding parameters for a given function f that make for -good randomness in the resulting engine's generated numbers x(i) -requires extensive and specialized mathematical training and -experience. In order to make good random numbers available to a large -number of library users, this proposal not only defines generic -random-number engines, but also provides a number of predefined -well-known good parameterizations for those. Usually, there are only -a few (less than five) well-known good parameterizations for each -engine, so it appears feasible to provide these. -

- -Since random-number engines are mathematically designed with computer -implementation in mind, parameters are usually integers representable -in a machine word, which usually coincides nicely with a C++ built-in -type. The parameters could either be given as (compile-time) template -arguments or as (run-time) constructor arguments. -

- -Providing parameters as template arguments allows for providing -predefined parameterizations as simple "typedef"s. Furthermore, the -parameters appear as integral constants, so the compiler can -value-check the given constants against the engine's base type. Also, -the library implementor can choose different implementations depending -on the values of the parameters, without incurring any runtime -overhead. For example, there is an efficient method to compute (a*x) -mod m, provided that a certain magnitude of m relative to the -underlying type is not exceeded. Additionally, the compiler's -optimizer can benefit from the constants and potentially produce -better code, for example by unrolling loops with fixed loop count. -

- -As an alternative, providing parameters as constructor arguments -allows for more flexibility for the library user, for example when -experimenting with several parameterizations. Predefined -parameterizations can be provided by defining wrapper types which -default the constructor parameters. -

- -Other libraries have hard-coded the parameters of their engines and do -not allow the user any configuration of them at all. If the user -wishes to change the parameters, he has to re-implement the engine's -algorithm. In my opinion, this approach unnecessarily restricts -re-use. -

- -Regarding initialization, this proposal chooses to provide -"deterministic seeding" with the default constructor and the -seed function without parameters: Two engines constructed -using the default constructor will output the same sequence. In -contrast, the CLHEP library's default constructed engines will take a -fresh seed from a seed table for each instance. While this approach -may be convenient for a certain group of users, it relies on global -state and can easily be emulated by appropriately wrapping engines -with deterministic seeding. -

- -In addition to the default constructor, all engines provide a -constructor and seed function taking an iterator range -[it1,it2) pointing to unsigned integral values. An engine initializes its state by successively consuming -values from the iterator range, then returning the advanced iterator it1. -This approach has the advantage that the user can completely exploit -the large state of some engines for initialization. Also, it allows -to initialize compound engines in a uniform manner. For example, a -compound engine consisting of two simpler engines would initialize the -first engine with its [it1,it2). The first engine returns a smaller -iterator range that it has not consumed yet. This can be used to -initialize the second engine. -

- -The iterator range [it1,it2) is specified to point to unsigned -long values. There is no way to determine from a generic user -program how the initialization values will be treated and what range -of bits must be provided, except by enumerating all engines, e.g. in -template specializations. The problem is that a given generator might -have differing requirements on the values of the seed range even -within one seed call. -

- -For example, imagine a - -

   xor_combine<lagged_fibonacci<...>, mersenne_twister<...> >
- -generator. For this, seed(first, last) will consume -values as follows: First, seed the state of the -lagged_fibonacci generator by consuming one item from -[first, last) for each word of state. The values are reduced to -(e.g.) 24 bits to fit the lagged_fibonacci state -requirements. Then, seed the state of the -mersenne_twister by consuming some number of items from -the remaining [first, last). The values are reduced to 32 bits to fit -the mersenne_twister state requirements. -

- -How does a concise programming interface for those increasingly -complex and varying requirements on [first, last) look like? I don't -know, and I don't want to complicate the specification by inventing -something complicated here. -

- -Thus, the specification says for each generator how it uses the seed -values, and how many are consumed. Additional features are left to -the user. -

- -In a way, this is similar to STL containers: It is intended that the user -can exchange iterators to various containers in generic algorithms, -but the container itself is not meant to be exchanged, i.e. having a -Container template parameter is often not adequate. That is analogous -to the random number case: The user can pass an engine around and use its -operator() and min and max -functions generically. However, the user can't generically query the -engine attributes and parameters, simply because most are entirely -different in semantics for each engine. -

- -The seed(first, last) interface can serve two purposes: - -

    -
  1. In a generic context, the user can pass several integer values >= 1 -for seeding. It is unlikely that the user explores the full state space -with the seeds she provides, but she can be reasonably sure that her -seeds aren't entirely incorrect. (There is no formal guarantee for that, except that -the ability to provide bad seeds usually means the parameterization of -the engine is bad, e.g. a non-prime modulus for a linear congruential -engine.) For example, if the user wants a seed(uint32_t) -on top of seed(first, last), one option is to use a -linear_congruential generator that produces the values -required for seed(first, last). When the user defines the -iterator type for first and last so that it -encapsulates the linear_congruential engine in -operator++, the user doesn't even need to know beforehand how -many values seed(first, last) will need.
  2. - -
  3. If the user is in a non-generic context, he knows the specific -template type of the engine (probably not the template value-based -parameterization, though). The precise specification for seed(first, -last) allows to know what values need to be passed in so -that a specific initial state is attained, for example to compare one -implementation of the engine with another one that uses different -seeding.
  4. - -
  5. If the user requires both, he needs to inject knowledge into (1) -so that he is in the position of (2). One way to inject the knowledge -is to use (partial) template specialization to add the knowledge. The -specific parameterization of some engine can then be obtained by -querying the data members of the engines.
  6. -
-

- -I haven't seen the iterator-based approach to engine initialization in -other libraries; most initialization approaches rely on a either a -single value or on per-engine specific approaches to initialization. -

- -An alternative approach is to pass a zero-argument function object -("generator") for seeding. It is trivial to implement a generator -from a given iterator range, but it is more complicated to implement -an iterator range from a generator. Also, the exception object that -is specified to be thrown when the iterator range is exhausted could -be configured in a user-provided iterator to generator mapping. -With this approach, some engines would have three one-argument constructors: -One taking a single integer for seeding, one taking a (reference?) to -a (templated) generator, and the copy constructor. It appears that the -opportunities for ambiguities or choosing the wrong overload are too -confusing to the unsuspecting user. - - -

F. Parameterization and Initialization for Distributions

- -The distributions specified in this proposal have template parameters -that indicate the output data type (e.g. float, -double, long double) that the user desires. -

- -The probability density functions of distributions usually have -parameters. These are mapped to constructor parameters, to be set at -runtime by the library user according to her requirements. The -parameters for a distribution object cannot change after its -construction. When constructing the distribution, this allows to -pre-compute some data according to the parameters given without risk -of inadvertently invalidating them later. -

- -Distributions may implement operator()(T x), for -arbitrary type T, to meet special needs, for example a -"one-shot" mode where each invocation uses different distribution -parameters. - - -

G. Properties as Traits vs. In-Class Constants

- -Users might wish to query compile-time properties of the engines and -distributions, e.g. their base types, constant parameters, etc. This -is similar to querying the properties of the built-in types such as -double using std::numeric_limits<>. However, -engines and distributions cannot be simple types, so it does not -appear to be necessary to separate the properties into separate traits -classes. Instead, compile-time properties are given as members types -and static member constants. - - -

H. Which Engines to Include

- -There is a multitude of pseudo-random number engines available in both -literature and code. Some engines, such as Mersenne Twister, have an -independent algorithm ("base engine"). Others change the values or -order of output of other engines to improve randomness, for example -Knuth's "Algorithm B" ("compound engine"). The template mechanism -allows easy combination of base and compound engines. -

- -Engines may be categorized according to the following dimensions. - -

    -
  • integers or floating-point numbers produced (Some engines produce -uniformly distributed integers in the range [min,max], however, most -distribution functions expect uniformly distributed floating-point -numbers in the range [0,1) as the input sequence. The obvious -conversion requires a relatively costly integer to floating-point -conversion plus a floating-point multiplication by -(max-min+1)-1 for each random number used. To save the -multiplication, some engines can directly produce floating-point -numbers in the range [0,1) by maintaining the state x(i) in an -appropriately normalized form, given a sufficiently good -implementation of basic floating-point operations (e.g. IEEE -754).
  • - -
  • quality of random numbers produced (What is the cycle length? -Does the engine pass all relevant statistical tests? Up to what -dimension are numbers equidistributed?)
  • - -
  • speed of generation (How many and what kind of operations have to -be performed to produce one random number, on average?)
  • - -
  • size of state (How may machine words of storage are required to -hold the state x(i) of the random engine?)
  • - -
  • option for independent subsequences (Is it possible to move from -x(i) to x(i+k) with at most O(log(k)) steps? This allows to -efficiently use subsequences x(0)...x(k-1), x(k)...x(2k-1), ..., -x(jk)...x((j+1)k-1), ..., for example for parallel computation, where -each of the m processors gets assigned the (independent) subsequence -starting at x(jk) (0 <= k < m).)
  • -
- -According to the criteria above, the engines given below were chosen. -The quality and size indications were completed according to best -known parameterizations. Other parameterizations usually yield poorer -quality and/or less size. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
engineint / floatqualityspeedsize of statesubsequencescomments
linear_congruentialintmediummedium1 wordyescycle length is limited to the maximum value representable in one -machine word, passes most statisticial tests with chosen -parameters.
mersenne_twisterintgoodfast624 wordsnolong cycles, passes all statistical tests, good -equidistribution in high dimensions
subtract_with_carrybothmediumfast25 wordsnovery long cycles possible, fails some statistical tests. Can be -improved with the discard_block compound engine.
discard_blockbothgoodslowbase engine + 1 wordnocompound engine that removes correlation provably by throwing away -significant chunks of the base engine's sequence, the resulting speed -is reduced to 10% to 3% of the base engine's.
xor_combineintgoodfastbase enginesyes, if one of the base enginescompound engine that XOR-combines the sequences of -two base engines
-

- -Some engines were considered for inclusion, but left out for the -following reasons: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
engineint / floatqualityspeedsize of statesubsequencescomments
shuffle_outputintgoodfastbase engine + 100 wordsnocompound engine that reorders the base engine's output, little -overhead for generation (one multiplication)
lagged_fibonaccibothmediumfastup to 80,000 wordsnovery long cycles possible, fails birthday spacings test. Same -principle of generation as subtract_with_carry, i.e. x(i) -= x(i-s) (*) x(i-r), where (*) is either of +, -, xor with or without -carry.
inversive_congruential (Hellekalek 1995)intgoodslow1 wordnox(i+1) = a x(i)-1 + c. Good equidistribution in -several dimensions. Provides no apparent advantage compared to -ranlux; the latter can produce floating-point numbers directly.
additive_combine (L'Ecuyer 1988)intgoodmedium2 wordsyesCombines two linear congruential generators. Same principle -of combination as xor_combine, i.e. z(i) = x(i) (*) y(i), -where (*) is one of +, -, xor.
R250 (Kirkpatrick and Stoll)intbadfast~ 20 wordsnoGeneral Feedback Shift Register with two taps: Easily exploitable -correlation.
linear_feedback_shiftintmediumfast1 wordnocycle length is limited to the maximum value representable in one -machine word, fails some statistical tests, can be improved with the -xor_combine compound engine.
-

- -The GNU Scientific Library and Swarm have additional engine that are -not mentioned in the table below. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Enginethis proposalCLHEPcrngGNU Scientific LibrarySwarmNumerical RecipesKnuth
LCG(231-1, 16807)minstd_rand0-ParkMillerran0, minstd-ran0p106, table 1, line 19
LCG(232, a=1664525, c=1013904223)linear_congruential< ..., 1664525, 1013904223, (1 << 32) >---LCG1gen-p106, table 1, line 16
LCG1 + LCG2 + LCG3--WichmannHill----
(LCG1 - LCG2 + LCG3 - LCG4) mod m0----C4LCGXgen--
LCG(231-1, 16807) with Bays/Durham shuffleshuffle_output<minstd_rand0, 32> (shuffle_output not in this -proposal)--ran1PMMLCG1genran1Algorithm "B"
(LCG(231-85, 40014) + LCG(231-249, 40692)) -mod 231-85ecuyer1988 (additive_combine not in this proposal)RanecuLEcuyer-C2LCGXgen--
(LCG(231-85, 40014) with Bays/Durham shuffle + -LCG(231-249, 40692)) mod 231-85additive_combine< - shuffle_output<
- linear_congruential<int, 40014, 0, 2147483563>, 32>,
- linear_congruential<int, 40692, 0, 2147483399> > -(additive_combine and shuffle_output not in this proposal)
--ran2-ran2-
X(i) = (X(i-55) - X(i-33)) mod 109---ran3~SCGgenran3-
X(i) = (X(i-100) - X(i-37)) mod 230------ran_array
X(i) = (X(i-55) + X(i-24)) mod 232lagged_fibonacci< ..., 32, 55, 24, ...> -(lagged_fibonacci not in this proposal) ----ACGgen--
DEShash(i,j)-----ran4-
MTmt19937MTwistEngineMT19937mt19937MT19937gen--
X(i) = (X(i-37) - X(i-24) - carry) mod 232subtract_with_carry< ..., (1<<32), 37, 24, ...>---SWB1gen--
X(i) = (X(i-43) - X(i-22) - carry) mod 232-5subtract_with_carry< ..., (1<<32)-5, 43, 22, ...>---PSWBgen--
RCARRY with block discard by Lüscherdiscard_block< subtract_with_carry<...>, ...>RanluxEngine, Ranlux64EngineRanluxranlx*---
Hurd-Hurd160, Hurd288-----
physical model by Ranshi-Ranshi-----
return predefined data-NonRandom-----
RANMAR: z(i) = (z(i-97) - z(i-33)) mod 224; y(i+1) = -(y(i)-c) mod 224-3; X(i) = (z(i) - y(i)) mod -224additive_combine< lagged_fibonacci< (1<<24), 97, 33, -... >, linear_congruential< (1<<24)-3, 1, c, ...> -(additive_combine and lagged_fibonacci not in this proposal) -JamesRandom-ranmar---
Taus88taus88 = xor_combine ...-Taus88taus, taus2---
Taus60xor_combine< linear_feedback_shift< 31, 13, 12 >, 0, -linear_feedback_shift< 29, 2, 4 >, 2, 0> -(linear_feedback_shift not in this proposal) ----C2TAUSgen--
GFSR, 4-tap---gfsr4---
MRG32k3a--MRG32k3a----
- - -

I. Which Distributions to Include

- -The following distributions were chosen due to their relatively -widespread use: - -
    -
  • Integer uniform -
  • Floating-point uniform -
  • Exponential -
  • Normal -
  • Gamma -
  • Poisson -
  • Binomial -
  • Geometric -
  • Bernoulli -
- -The GNU Scientific Library has a multitude of additional distributions -that are not mentioned in the table below. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Distributionthis proposalCLHEPcrngGNU Scientific LibrarySwarmNumerical RecipesKnuth
uniform (int)uniform_int---UniformIntegerDist--
uniform (float)uniform_realRandFlatUniformDeviateflatUniformDoubleDist-uniform
exponentialexponential_distributionRandExponentialExponentialDeviateexponentialExponentialDistexponentialexponential
normalnormal_distributionRandGauss*NormalDeviategaussianNormalDistnormal (gaussian)normal
lognormal---lognormalLogNormalDist--
gammagamma_distributionRandGammaGammaDeviategammaGammaDistgammagamma
beta--BetaDeviatebeta--beta
poissonpoisson_distributionPoissonPoissonDeviatepoissonPoissonDistpoissonpoisson
binomialbinomial_distributionRandBinomialBinomialDeviatebinomial-binomialbinomial
geometricgeometric_distribution-GeometricDeviategeometric--geometric
bernoullibernoulli_distribution-BernoulliDeviatebernoulliBernoulliDist--
random bit-RandBit--RandomBitDist--
breit-wigner-RandBreitWigner-----
chi-square-RandChiSquare-chisq--chi-square
landau-Landau-landau---
F---F--F (variance-ratio)
t---t--t
- - -

J. Taxonomy of Concepts

- -All of the engines support the number generator requirements, -i.e. they are zero-argument function objects which return numbers. -All of the distributions are one-argument function objects, taking a -reference to an engine and returning numbers. All of the engines and -some of the distributions return uniformly distributed random numbers. -This is reflected in the concept of the uniform random number -generator, which refines number generator. Engines for pseudo-random -numbers model the requirements for pseudo-random number engine, which -refines uniform random number generator. - -
-NumberGenerator ---- UniformRandomNumberGenerator ---- PseudoRandomNumberGenerator
-                \--- RandomDistribution
-
- - -

K. Validation

- -How can a user have confidence that the implementation of a -random-number engine is exactly as specified, correctly taking into -account any platform pecularities (e.g., odd-sized ints)? After all, -minor typos in the implementation might not be apparent; the numbers -produced may look "random". This proposal therefore specifies for -each engine the 10000th number in the random number sequence that a -default-constructed engine object produces. -

- -This is considered an important feature for library implementors and -serious users to check whether the provided library on the given -platform returns the correct numbers. It could be argued that a -library implementor should provide a correct implementation of some -standard feature in any case. -

- -No other library I have encountered provides explicit validation -values in either their specification or their implementation, although -some of them claim to be widely portable. -

- -Another design option for validation that was part of early drafts of -this proposal is moving the reference number (10000th value in the -sequence) from specification space to implementation space, thus -providing a validation(x) static member function for each -engine that compares the hard-coded 10000th value of the sequence with -some user-provided value x presumeably obtained by -actually invoking the random-number engine object 10000 times. Due to -the template-based design, this amounted to a "val" template value -parameter for each engine, and the validation(x) function -reduced to the trivial comparison "val == x". Handling validation for -floating-point engines required more machinery, because template value -parameters cannot be of floating-point type. Also, from a conceptual -perspective, it seemed odd to demand a validation decision from the -very entitiy which one wanted to validate. - - -

L. Non-Volatile Storage of Engine and Distribution State

- -Pseudo-random number engines and distributions may store their state on a -std::ostream in textual form and recover it from an -appropriate std::istream. Each engine specifies how its -internal state is represented. The specific algorithm of a -distribution is left implementation-defined, thus no specifics about -the representation of its internal state are given. A store operation -must not affect the number sequence produced. It is expected -that such external storage happens rarely as opposed to producing -random numbers, thus no particular attention to performance is paid. -

- -Engines and distributions use the usual idioms of operator<< and -operator>>. If the user needs additional -processing before or after storage on non-volatile media, there is -always the option to use a temporary std::stringstream. -

- -Distributions sometimes store values from their associated source of -random numbers across calls to their operator(). For example, a -common method for generating normally distributed random numbers is to -retrieve two uniformly distributed random numbers and compute two -normally distributed random numbers out of them. -In order to reset the distribution's random number cache to a defined -state, each distribution has a reset member function. It -should be called on a distribution whenever its associated engine is -exchanged or restored. - - -

M. Values vs. References

- -Compounded engines such as shuffle_output and -discard_block contain a base engine by value, because -compounding is not intended to be used by reference to an existing -(re-used) engine object. -

- -The wrapper variate_generator can store engines either by -value or by reference, explicitly chosen by the template parameters. -This allows to use references to a single engine in several -variate_generator, but makes it explicit to the user that -he is responsible for the management of the lifetime of the engine. - - -

N. Providing the Probability Density Function in Distributions

- -Some libraries provide the probability density function of a given -distribution as part of that distribution's interface. While this may -be useful occasionally, this proposal does not provide for such a -feature. One reason is separation of concerns: The distribution class -templates might benefit from precomputing large tables of values -depending on the distribution parameters, while the computation of the -probability density function does not. Also, the function -representation is often straightforward, so the user can easily code -it himself. - - -

O. Implementation-defined behaviour

- -This proposal specifies implementation-defined behaviour in a number -of places. I believe this is unavoidable; this section provides -detailed reasoning, including why the implementation is required to -document the choice. -

- -The precise state-holding base data types for the various engines are -left implementation-defined, because engines are usually optimized for -binary integers with 32 bits of word size. The specification in this -proposal cannot foresee whether a 32 bit quantity on the machine is -available in C++ as short, int, long, or not at all. It is up to the -implementation to decide which data type fits best. The -implementation is required to document the choice of data type, so -that users can (non-portably) rely on the precise type, for example -for further computation. Should the ISO C99 extensions become part of -ISO C++, the implementation-defined types could be replaced by -e.g. int_least32_t. -

- -The method how to produce non-deterministic random numbers is -considered implementation-defined, because it inherently depends on -the implementation and possibly even on the runtime environment: -Imagine a platform that has operating system support for randomness -collection, e.g. from user keystrokes and Ethernet inter-packet -arrival timing (Linux /dev/random does this). If, in some -installation, access to the operating system functions providing these -services has been restricted, the C++ non-deterministic random number -engine has been deprived of its randomness. An implementation is -required to document how it obtains the non-deterministic random -numbers, because only then can users' confidence in them grow. -Confidence is of particular concern in the area of cryptography. -

- -The algorithms how to produce the various distributions are specified -as implementation-defined, because there is a vast variety of -algorithms known for each distribution. Each has a different -trade-off in terms of speed, adaptation to recent computer -architectures, and memory use. The implementation is required to -document its choice so that the user can judge whether it is -acceptable quality-wise. - - -

P. Lower and upper bounds on UniformRandomNumberGenerator

- -The member functions min() and max() return -the lower and upper bounds of a UniformRandomNumberGenerator. This -could be a random-number engine or one of the uniform_int -and uniform_real distributions. -

- -Those bounds are not specified to be tight, because for some engines, -the bounds depend on the seeds. The seed can be changed during the -lifetime of the engine object, while the values returned by -min() and max() are invariant. Therefore, -min() and max() must return conservative -bounds that are independent of the seed. - - -

Q. With or without manager class

- -This proposal presents a design with a manager class template, -variate_generator, after extensive discussion with some -members of the computing division of Fermi National Accelerator -Laboratory. User-written and library-provided engines and -distributions plug in to the manager class. The approach is remotely -similar to the locale design in the standard library, where -(user-written) facets plug in to the (library-provided) locale class. -

- -Earlier versions of this propsoal made (potentially user-written) -distributions directly visible to (some other) user that wants to get -random numbers distributed accordingly ("client"), there was no -additional management layer between the distribution and the client. -

- -The following additional features could be provided by the management -layer: - -

    -
  • The management layer contains an adaptor (to convert the engine's -output into the distribution's input) in addition to the engine and -the distribution.
  • - -
  • Adaptors and distributions do not store state, but instead, in -each invocation, consume an arbitrary number of input values and -produce a fixed number of output values. The management layer is -responsible for connecting the engine - adaptor - distribution chain, -invoking each part when more numbers are needed from the next part of -the chain. - -
  • On request, the management layer is responsible for saving and -restoring the buffers that exist between engine, adaptor, and -distribution.
  • - -
  • On request, the management layer shares engines with another -instance of the management layer.
  • - -
- -It is envisioned that user-written distributions will often be based -on some arbitrary algorithmic distribution, instead of trying to -implement a given mathematical probability density function. Here is -an example: -
    -
  • Retrieve a uniform integer with value either 1 or 2. -
  • If 1, return a number with normal distribution. -
  • If 2, return a number with gamma distribution. -
- -Both in this case and when implementing complex distributions based on -a probability density function (e.g. the gamma distribution), it is -important to be able to arbitrarily nest distributions. Either design -allows for this with utmost ease: Compounding -distributions are contained in the compound by value, and each one -produces a single value on invocation. With the alternative design of -giving distributions the freedom to produce -more than one output number in each invocation, compound distributions -such as the one shown above need to handle the situation that each of -the compounding members could provide several output values, the -number of which is unknown at the time the distribution is written. -(Remember that it is unfeasible to prescribe a precise algorithm for -each library-provided distribution in the standard, see subsection O.) -That approach shifts implementation effort from the place where it -came up, i.e. the distribution that chose to use an algorithm that -produces several values in one invocation, to the places where that -distribution is used. This, considered by itself, does not seem to be -a good approach. Also, only very few distributions lead to a natural -implementation that produces several values in one invocation; so far, -the normal distribution is the only one known to me. However, it is -expected that there will be plenty of distributions that use a normal -distribution as its base, so far those known to me are lognormal and -uniform_on_sphere (both not part of this proposal). As a conclusion, -independent of whether the design provides for a management layer or -not, distributions should always return a single value on each -invocation, and management of buffers for additional values that might -be produced should be internal to the distribution. Should it become -necessary for the user to employ buffer management more often, a -user-written base class for the distributions could be of help. -

- -The ability to share engines is important. This proposal makes -lifetime management issues explicit by requiring pointer or reference -types in the template instantiation of variate_generator -if reference semantics are -desired. Without a management class, providing this features is -much more cumbersome and imposes additional burden on the programmers -that produce distributions. Alternatively, reference semantics could -always be used, but this is an -error-prone approach due to the lack of a standard reference-counted -smart pointer. I believe it is impossible to add a reference-counted -sharing mechanism in a manager-class-free design without giving its precise -type. And that would certainly conflict in semantic scope with a -smart pointer that will get into the standard eventually. -

- -The management layer allows for a few common features to be factored -out, in particular access to the engine and some member typedefs. -

- -Comparison of other differing features between manager and non-manager -designs: - -

    -
  • When passing a variate_generator as a an argument to -a function, the design in this proposal allows selecting only those -function signatures during overload resolution that are intended to be -called with a variate_generator. In contrast, -misbehaviour is possible without a manager class, similar to -iterators in function signatures: template<class BiIter> -void f(BiIter it) matches f(5), without regard to -the bidirectional iterator requirements. An error then happens when -instantiating f. The situation worsens when several competing -function templates are available and the wrong one is chosen -accidentally. - -
  • With the engine passed into the distribution's constructor, the -full type hierarchy of engine (and possibly adaptor) are available to -the distribution, allowing to cache information derived from the -engine (e.g. its value range) . Also, (partial) specialization -of distributions could be written that optimize the interaction with a -specific engine and/or adaptor. In this proposal's design, -this information is available in the variate_generator template -only. However, optimizations by specialization for the -engine/adaptor combination are perceived to possibly have high -benefit, while those for the (engine+adaptor) / distribution -combination are presumed to be much less beneficial. - -
  • Having distribution classes directly exposed to the client easily -allows that the user writes a distribution with an additional -arbitrary member function declaration, intended to produce random -numbers while taking additional parameters into account. In this -proposal's design, this is possible by using the -generic operator()(T x) forwarding function. - -
- - -

R. Add-on packages

- -This proposal specifies a framework for random number generation. -Users might have additional requirements not met by this framework. -The following extensions have been identified, and they are expressly not -addressed in this proposal. It is perceived that these items can be -seamlessly implemented in an add-on package which sits on top of an -implementation according to this proposal. - -
    -
  • unique seeding: Make it easy for the user to provide a unique seed -for each instance of a pseudo-random number engine. Design idea: -
    -  class unique_seed;
    -
    -  template<class Engine>
    -  Engine seed(unique_seed&);
    -
    -The "seed" function retrieves some unique seed from the unique_seed -class and then uses the seed(first, last) interface of an -engine to implant that unique seed. Specific seeding requirements for -some engine can be met by (partial) template specialization.
  • -

    - -

  • runtime-replaceable distributions and associated save/restore -functionality: Provide a class hierarchy that invokes distributions by -means of a virtual function, thereby allowing for runtime replacement -of the actual distribution. Provide a factory function to reconstruct -the distribution instance after saving it to some non-volatile media. - -
- - -

S. Adaptors

- -Sometimes, users may want to have better control how the bits from the -engine are used to fill the mantissa of the floating-point value that -serves as input to some distribution. This is possible by writing an -engine wrapper and passing that in to the variate_generator as the -engine. The variate_generator will only apply automatic adaptations -if the output type of the engine is integers and the input type for -the distribution is floating-point or vice versa. - - -

Z. Open issues

- -
    -
  • Some engines require non-negative template arguments, usually bit -counts. Should these be given as "int" or "unsigned int"? Using -"unsigned int" sometimes adds significant clutter to the -presentation. Or "size_t", but this is probably too large a type?
  • - -
- - - -

IV. Proposed Text

- -(Insert the following as a new section in clause 26 "Numerics". -Adjust the overview at the beginning of clause 26 accordingly.) -

- -This subclause defines a facility for generating random numbers. - - -

Random number requirements

- -A number generator is a function object (std:20.3 -[lib.function.objects]). -

- -In the following table, X denotes a number generator -class returning objects of type T, and u is -a (possibly const) value of X. -

- - - - - - - - - - - - - - - - - - - - -
Number generator requirements (in addition -to function object)
expressionreturn typepre/post-conditioncomplexity
X::result_typeTstd::numeric_limits<T>::is_specialized is -truecompile-time
-

- -In the following table, X denotes a uniform random number -generator class returning objects of type T, -u is a value of X and v is a -(possibly const) value of X. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Uniform random number generator -requirements (in addition to number generator)
expressionreturn typepre/post-conditioncomplexity
u()T-amortized constant
v.min()TReturns some l where l is less than or equal to all values -potentially returned by operator(). -The return value of this function shall not change during the lifetime -of v.constant
v.max()TIf std::numeric_limits<T>::is_integer, returns -l where l is less than or equal to all values potentially returned by -operator(), otherwise, returns l where l is strictly less than all -values potentially returned by operator(). In any case, -the return value of this function shall not change during the lifetime -of v.constant
- -

-In the following table, X denotes a pseudo-random number -engine class returning objects of type T, t -is a value of T, u is a value of -X, v is an lvalue of X, -it1 is an lvalue and it2 is a (possibly -const) value of an input iterator type It -having an unsigned integral value type, x, y -are (possibly const) values of -X, os is convertible to an lvalue of type -std::ostream, and is is convertible to an -lvalue of type std::istream. -

-A pseudo-random number engine x has a state x(i) at any given time. -The specification of each pseudo-random number engines defines the size of its -state in multiples of the size of its result_type, given -as an integral constant expression. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Pseudo-random number engine requirements -(in addition to uniform random number generator, -CopyConstructible, and Assignable)
expressionreturn typepre/post-conditioncomplexity
X()-creates an engine with the same initial state as all other -default-constructed engines of type X in the -program.O(size of state)
X(it1, it2)-creates an engine with the initial state given by the range -[it1,it2). it1 is advanced by the size of -state. If the size of the range [it1,it2) is insufficient, leaves -it1 == it2 and throws invalid_argument.O(size of state)
u.seed()voidpost: u == X()O(size of state)
u.seed(it1, it2)voidpost: If there are sufficiently many values in [it1, it2) to -initialize the state of u, then u == -X(it1,it2). Otherwise, it1 == it2, throws -invalid_argument, and further use of u -(except destruction) is undefined until a seed member -function has been executed without throwing an exception.O(size of state)
u()T -given the state u(i) of the engine, computes u(i+1), sets the -state to u(i+1), and returns some output dependent on u(i+1)amortized constant
x == ybool== is an equivalence relation. The current state x(i) -of x is equal to the current state y(j) of y.O(size of state)
x != ybool!(x == y)O(size of state)
os << xstd::ostream&writes the textual representation of the state x(i) of -x to os, with -os.fmtflags set to -ios_base::dec|ios_base::fixed|ios_base::left and the fill -character set to the space character. In the output, adjacent numbers -are separated by one or more space characters. -
-post: The os.fmtflags and fill character are -unchanged.
O(size of state)
is >> vstd::istream&sets the state v(i) of v as determined by reading its -textual representation from is. -
-post: The is.fmtflags are unchanged.
O(size of state)
-

- -In the following table, X denotes a random distribution -class returning objects of type T, u is a -value of X, x is a (possibly const) -value of X, and e is an lvalue of an -arbitrary type that meets the requirements of a uniform random number -generator, returning values of type U. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Random distribution requirements -(in addition to number generator, -CopyConstructible, and Assignable)
expressionreturn typepre/post-conditioncomplexity
X::input_typeU-compile-time
u.reset()voidsubsequent uses of u do not depend on values -produced by e prior to invoking reset.constant
u(e)Tthe sequence of numbers returned by successive invocations with -the same object e is randomly distributed with some -probability density function p(x)amortized constant number of invocations of e
os << xstd::ostream&writes a textual representation for the parameters and additional -internal data of the distribution x to os. -
-post: The os.fmtflags and fill character are -unchanged.
O(size of state)
is >> ustd::istream&restores the parameters and additional internal data of the -distribution u. -
-pre: is provides a textual representation that was -previously written by operator<< -
-post: The is.fmtflags are unchanged.
O(size of state)
-

- -Additional requirements: The sequence of numbers produced by -repeated invocations of x(e) does not change whether or -not os << x is invoked between any of the -invocations x(e). If a textual representation -is written using os << x and that representation -is restored into the same or a different object y of the -same type using is >> y, repeated invocations of -y(e) produce the same sequence of random numbers as would -repeated invocations of x(e). -

- -In the following subclauses, a template parameter named -UniformRandomNumberGenerator shall denote a class that -satisfies all the requirements of a uniform random number generator. -Moreover, a template parameter named Distribution shall -denote a type that satisfies all the requirements of a random -distribution. -Furthermore, a template parameter named RealType shall -denote a type that holds an approximation to a real number. This type -shall meet the requirements for a numeric type (26.1 -[lib.numeric.requirements]), the binary operators +, -, *, / shall be -applicable to it, a conversion from double shall exist, -and function signatures corresponding to those -for type double in subclause 26.5 [lib.c.math] shall be -available by argument-dependent lookup (3.4.2 [basic.lookup.koenig]). -[Note: The built-in floating-point types float -and double meet these requirements.] - - -

Header <random> synopsis

- -
-namespace std {
-  template<class UniformRandomNumberGenerator, class Distribution>
-  class variate_generator;
-
-  template<class IntType, IntType a, IntType c, IntType m>
-  class linear_congruential;
-
-  template<class UIntType, int w, int n, int m, int r, UIntType a, int u,
-  int s, UIntType b, int t, UIntType c, int l>
-  class mersenne_twister;
-
-  template<class IntType, IntType m, int s, int r>
-  class subtract_with_carry;
-
-  template<class RealType, int w, int s, int r>
-  class subtract_with_carry_01;
-
-  template<class UniformRandomNumberGenerator, int p, int r>
-  class discard_block;
-
-  template<class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  class xor_combine;
-
-  class random_device;
-
-  template<class IntType = int>
-  class uniform_int;
-
-  template<class RealType = double>
-  class bernoulli_distribution;
-
-  template<class IntType = int, class RealType = double>
-  class geometric_distribution;
-
-  template<class IntType = int, class RealType = double>
-  class poisson_distribution;
-
-  template<class IntType = int, class RealType = double>
-  class binomial_distribution;
-
-  template<class RealType = double>
-  class uniform_real;
-
-  template<class RealType = double>
-  class exponential_distribution;
-
-  template<class RealType = double>
-  class normal_distribution;
-
-  template<class RealType = double>
-  class gamma_distribution;
-
-} // namespace std
-
- - -

Class template variate_generator

- -A variate_generator produces random numbers, drawing -randomness from an underlying uniform random number generator and -shaping the distribution of the numbers corresponding to a -distribution function. -
-template<class Engine, class Distribution>
-class variate_generator
-{
-public:
-  typedef Engine engine_type;
-  typedef /* implementation defined */ engine_value_type;
-  typedef Distribution distribution_type;
-  typedef typename Distribution::result_type result_type;
-
-  variate_generator(engine_type eng, distribution_type d);
-
-  result_type operator()();
-  template<class T>  result_type operator()(T value);
-
-  engine_value_type& engine();
-  const engine_value_type& engine() const;
-
-  distribution_type& distribution();
-  const distribution_type& distribution() const;
-
-  result_type min() const;
-  result_type max() const;
-};
-
- -The template argument for the parameter Engine shall be -of the form U, U&, or -U*, where U denotes a -class that satisfies all the requirements of a uniform random number -generator. The member engine_value_type shall name -U. -

- -Specializations of variate_generator satisfy the -requirements of CopyConstructible. They also satisfy the requirements -of Assignable unless the template parameter Engine is of -the form U&. -

- -The complexity of all functions specified in this section is constant. -No function described in this section except the constructor throws an -exception. -

- -

    variate_generator(engine_type eng, distribution_type d)
-Effects: Constructs a variate_generator -object with the associated uniform random number generator -eng and the associated random distribution -d. -
-Throws: If and what the copy constructor of Engine or -Distribution throws. - -
    result_type operator()()
-Returns: distribution()(e) -
-Notes: The sequence of numbers produced by the -uniform random number generator e, se, is -obtained from the sequence of numbers produced by the associated -uniform random number generator eng, seng, as -follows: Consider the values of -numeric_limits<T>::is_integer for -T both Distribution::input_type and -engine_value_type::result_type. If the values for both -types are true, then se is identical to -seng. Otherwise, if the values for both types are -false, then the numbers in seng are divided by -engine().max()-engine().min() to obtain the -numbers in se. Otherwise, if the value for -engine_value_type::result_type is true and -the value for Distribution::input_type is -false, then the numbers in seng are divided by -engine().max()-engine().min()+1 to obtain the -numbers in se. Otherwise, the mapping from seng -to se is implementation-defined. In all cases, an implicit -conversion from engine_value_type::result_type to -Distribution::input_type is performed. If such a -conversion does not exist, the program is ill-formed. - -
    template<class T> result_type operator()(T value)
-Returns: distribution()(e, value). For -the semantics of e, see the description of -operator()(). - -
    engine_value_type& engine()
-Returns: A reference to the associated uniform random -number generator. - -
    const engine_value_type& engine() const
-Returns: A reference to the associated uniform random -number generator. - -
    distribution_type& distribution()
-Returns: A reference to the associated random -distribution. - -
    const distribution_type& distribution() const
-Returns: A reference to the associated random -distribution. - -
    result_type min() const
-Precondition: distribution().min() is -well-formed -
-Returns: distribution().min() - -
    result_type max() const
-Precondition: distribution().max() is -well-formed -
-Returns: distribution().max() - - -

Random number engine class templates

- -Except where specified otherwise, the complexity of all functions specified in -the following sections is constant. No function described in this -section except the constructor and seed functions taking an iterator -range [it1,it2) throws an exception. -

- -The class templates specified in this section satisfy all the -requirements of a pseudo-random number engine (given in tables in -section x.x), except where specified otherwise. Descriptions are -provided here only for operations on the engines that are not -described in one of these tables or for operations where there is -additional semantic information. -

- -All members declared static const in any of the following -class templates shall be defined in such a way that they are usable as -integral constant expressions. - - -

Class template linear_congruential

- -A linear_congruential engine produces random numbers -using a linear function x(i+1) := (a * x(i) + c) mod m. - -
-namespace std {
-  template<class IntType, IntType a, IntType c, IntType m>
-  class linear_congruential
-  {
-  public:
-    // types
-    typedef IntType result_type;
-
-    // parameter values
-    static const IntType multiplier = a;
-    static const IntType increment = c;
-    static const IntType modulus = m;
-
-    //  constructors and member function
-    explicit linear_congruential(IntType x0 = 1);
-    template<class In> linear_congruential(In& first, In last);
-    void seed(IntType x0 = 1);
-    template<class In> void seed(In& first, In last);
-    result_type min() const;
-    result_type max() const;
-    result_type operator()();
-  };
-
-  template<class IntType, IntType a, IntType c, IntType m>
-  bool operator==(const linear_congruential<IntType, a, c, m>& x,
-                  const linear_congruential<IntType, a, c, m>& y);
-  template<class IntType, IntType a, IntType c, IntType m>
-  bool operator!=(const linear_congruential<IntType, a, c, m>& x,
-                  const linear_congruential<IntType, a, c, m>& y);
-
-  template<class CharT, class traits,
-           class IntType, IntType a, IntType c, IntType m>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const linear_congruential<IntType, a, c, m>& x);  
-  template<class CharT, class traits,
-           class IntType, IntType a, IntType c, IntType m>
-  basic_istream<CharT, traits>& operator>>(basic_istream<CharT, traits>& is, 
-                                           linear_congruential<IntType, a, c, m>& x);
-}
-
- -The template parameter IntType shall denote an integral -type large enough to store values up to (m-1). If the template -parameter m is 0, the behaviour is -implementation-defined. Otherwise, the template parameters -a and c shall be less than m. -

- -The size of the state x(i) is 1. - - -

    explicit linear_congruential(IntType x0 = 1)
-Requires: c > 0 || (x0 % m) > 0 -
-Effects: Constructs a -linear_congruential engine with state x(0) := -x0 mod m. - -
    void seed(IntType x0 = 1)
-Requires: c > 0 || (x0 % m) > 0 -
-Effects: Sets the state x(i) of the engine to -x0 mod m. - -
    template<class In> linear_congruential(In& first, In last)
-Requires: c > 0 || *first > 0 -
-Effects: Sets the state x(i) of the engine to -*first mod m. -
-Complexity: Exactly one dereference of -*first. - - -
-  template<class CharT, class traits,
-           class IntType, IntType a, IntType c, IntType m>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const linear_congruential<IntType, a, c, m>& x);  
-
-Effects: Writes x(i) to os. - - -

Class template mersenne_twister

- -A mersenne_twister engine produces random numbers -o(x(i)) using the following computation, performed modulo -2w. um is a value with only the upper -w-r bits set in its binary representation. -lm is a value with only its lower r bits set -in its binary representation. rshift is a bitwise right -shift with zero-valued bits appearing in the high bits of the result. -lshift is a bitwise left shift with zero-valued bits -appearing in the low bits of the result. - -
    -
  • y(i) = (x(i-n) bitand um) | (x(i-(n-1)) bitand lm) -
  • If the lowest bit of the binary representation of y(i) is set, -x(i) = x(i-(n-m)) xor (y(i) rshift 1) xor a; -otherwise x(i) = x(i-(n-m)) xor (y(i) rshift 1). -
  • z1(i) = x(i) xor ( x(i) rshift u ) -
  • z2(i) = z1(i) xor ( (z1(i) lshift s) bitand b ) -
  • z3(i) = z2(i) xor ( (z2(i) lshift t) bitand c ) -
  • o(x(i)) = z3(i) xor ( z3(i) rshift l ) -
- -
-namespace std {
-  template<class UIntType, int w, int n, int m, int r, UIntType a, int u,
-  int s, UIntType b, int t, UIntType c, int l>
-  class mersenne_twister
-  {
-  public:
-    // types
-    typedef UIntType result_type;
-
-    // parameter values
-    static const int word_size = w;
-    static const int state_size = n;
-    static const int shift_size = m;
-    static const int mask_bits = r;
-    static const UIntType parameter_a = a;
-    static const int output_u = u;
-    static const int output_s = s;
-    static const UIntType output_b = b;
-    static const int output_t = t;
-    static const UIntType output_c = c;
-    static const int output_l = l;
-
-    //  constructors and member function
-    mersenne_twister();
-    explicit mersenne_twister(UIntType value);
-    template<class In> mersenne_twister(In& first, In last);
-    void seed();
-    void seed(UIntType value);
-    template<class In> void seed(In& first, In last);
-    result_type min() const;
-    result_type max() const;
-    result_type operator()();
-  };
-
-  template<class UIntType, int w, int n, int m, int r, UIntType a, int u,
-           int s, UIntType b, int t, UIntType c, int l>
-  bool operator==(const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& y,
-                  const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& x);
-  template<class UIntType, int w, int n, int m, int r, UIntType a, int u,
-           int s, UIntType b, int t, UIntType c, int l>
-  bool operator!=(const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& y,
-                  const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& x);
-
-  template<class CharT, class traits,
-           class UIntType, int w, int n, int m, int r, UIntType a, int u,
-           int s, UIntType b, int t, UIntType c, int l>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& x);
-  template<class CharT, class traits,
-           class UIntType, int w, int n, int m, int r, UIntType a, int u,
-           int s, UIntType b, int t, UIntType c, int l>
-  basic_istream<CharT, traits>& operator>>(basic_istream<CharT, traits>& is, 
-                                           mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& x);
-}
-
- -The template parameter UIntType shall denote an unsigned -integral type large enough to store values up to -2w-1. Also, the following relations shall hold: -1<=m<=n. 0<=r,u,s,t,l<=w. 0<=a,b,c<=2w-1. -

- -The size of the state x(i) is n. - - -

    mersenne_twister()
-Effects: Constructs a mersenne_twister -engine and invokes seed(). - -
    explicit mersenne_twister(result_type value)
-Effects: Constructs a mersenne_twister -engine and invokes seed(value). - -
    template<class In> mersenne_twister(In& first, In last)
-Effects: Constructs a mersenne_twister -engine and invokes seed(first, last). - -
    void seed()
-Effects: Invokes -seed(4357). - -
    void seed(result_type value)
-Requires: value > 0 -
-Effects: With a linear congruential generator l(i) -having parameters ml = 232, al = 69069, -cl = 0, and l(0) = value, sets x(-n) ... x(-1) -to l(1) ... l(n), respectively. -
-Complexity: O(n) - -
    template<class In> void seed(In& first, In last)
-Effects: Given the values z0 -... zn-1 obtained by dereferencing [first, first+n), sets -x(-n) ... x(-1) to z0 mod 2w -... zn-1 mod 2w. -
-Complexity: Exactly n dereferences of -first. - -
-    template<class UIntType, int w, int n, int m, int r, UIntType a, int u,
-             int s, UIntType b, int t, UIntType c, int l>
-    bool operator==(const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& y,
-                    const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& x)
-
-Returns: x(i-n) == y(j-n) and ... and x(i-1) == -y(j-1) -
-Notes: Assumes the next output of x is -o(x(i)) and the next output of y is o(y(j)). -
-Complexity: O(n) - -
-    template<class CharT, class traits,
-             class UIntType, int w, int n, int m, int r, UIntType a, int u,
-             int s, UIntType b, int t, UIntType c, int l>
-    basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                             const mersenne_twister<UIntType, w, n, m, r, a, u, s, b, t, c, l>& x)
-
-Effects: Writes x(i-n), ... x(i-1) to -os, in that order. -
-Complexity: O(n) - - -

Class template subtract_with_carry

- -A subtract_with_carry engine produces integer random numbers -using x(i) = (x(i-s) - x(i-r) - carry(i-1)) mod m; carry(i) = 1 if -x(i-s) - x(i-r) - carry(i-1) < 0, else carry(i) = 0. -

- -

-namespace std {
-  template<class IntType, IntType m, int s, int r>
-  class subtract_with_carry
-  {
-  public:
-    // types
-    typedef IntType result_type;
-
-    // parameter values
-    static const IntType modulus = m;
-    static const int long_lag = r;
-    static const int short_lag = s;
-
-    //  constructors and member function
-    subtract_with_carry();
-    explicit subtract_with_carry(IntType value);
-    template<class In> subtract_with_carry(In& first, In last);
-    void seed(IntType value = 19780503);
-    template<class In> void seed(In& first, In last);
-    result_type min() const;
-    result_type max() const;
-    result_type operator()();
-  };
-  template<class IntType, IntType m, int s, int r>
-  bool operator==(const subtract_with_carry<IntType, m, s, r> & x,
-                  const subtract_with_carry<IntType, m, s, r> & y);
-
-  template<class IntType, IntType m, int s, int r>
-  bool operator!=(const subtract_with_carry<IntType, m, s, r> & x,
-                  const subtract_with_carry<IntType, m, s, r> & y);
-
-  template<class CharT, class Traits,
-           class IntType, IntType m, int s, int r>
-  std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& os,
-                                               const subtract_with_carry<IntType, m, s, r>& f);
-
-  template<class CharT, class Traits,
-          class IntType, IntType m, int s, int r>
-  std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& is, 
-                                               subtract_with_carry<IntType, m, s, r>& f);
-}
-
- -The template parameter IntType shall denote a signed -integral type large enough to store values up to m-1. The following -relation shall hold: 0<s<r. Let w the number of bits in the -binary representation of m. -

- -The size of the state is r. - -

    subtract_with_carry()
-Effects: Constructs a subtract_with_carry -engine and invokes seed(). - -
    explicit subtract_with_carry(IntType value)
-Effects: Constructs a subtract_with_carry -engine and invokes seed(value). - -
    template<class In> subtract_with_carry(In& first, In last)
-Effects: Constructs a subtract_with_carry -engine and invokes seed(first, last). - -
    void seed(IntType value = 19780503)
-Requires: value > 0 -
-Effects: With a linear congruential generator l(i) -having parameters ml = 2147483563, al = 40014, -cl = 0, and l(0) = value, sets x(-r) ... x(-1) -to l(1) mod m ... l(r) mod m, respectively. If x(-1) == 0, sets -carry(-1) = 1, else sets carry(-1) = 0. -
-Complexity: O(r) - -
    template<class In> void seed(In& first, In last)
-Effects: With n=w/32+1 (rounded downward) and given -the values z0 ... zn*r-1 obtained by -dereferencing [first, first+n*r), sets x(-r) ... x(-1) to -(z0 * 232 + ... + zn-1 * -232*(n-1)) mod m ... (z(r-1)*n * 232 -+ ... + zr-1 * 232*(n-1)) mod m. If x(-1) == 0, -sets carry(-1) = 1, else sets carry(-1) = 0. -
-Complexity: Exactly r*n dereferences of -first. - -
-    template<class IntType, IntType m, int s, int r>
-    bool operator==(const subtract_with_carry<IntType, m, s, r> & x,
-                    const subtract_with_carry<IntType, m, s, r> & y)
-
-Returns: x(i-r) == y(j-r) and ... and x(i-1) == -y(j-1). -
-Notes: Assumes the next output of x is -x(i) and the next output of y is y(j). -
-Complexity: O(r) - -
-    template<class CharT, class Traits,
-          class IntType, IntType m, int s, int r>
-    std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& os,
-                                                 const subtract_with_carry<IntType, m, s, r>& f)
-
-Effects: Writes x(i-r) ... x(i-1), carry(i-1) to -os, in that order. -
-Complexity: O(r) - - -

Class template subtract_with_carry_01

- -A subtract_with_carry_01 engine produces floating-point -random numbers using x(i) = (x(i-s) - x(i-r) - carry(i-1)) mod 1; -carry(i) = 2-w if x(i-s) - x(i-r) - carry(i-1) < 0, else -carry(i) = 0. -

- -

-namespace std {
-  template<class RealType, int w, int s, int r>
-  class subtract_with_carry_01
-  {
-  public:
-    // types
-    typedef RealType result_type;
-
-    // parameter values
-    static const int word_size = w;
-    static const int long_lag = r;
-    static const int short_lag = s;
-
-    //  constructors and member function
-    subtract_with_carry_01();
-    explicit subtract_with_carry_01(unsigned int value);
-    template<class In> subtract_with_carry_01(In& first, In last);
-    void seed(unsigned int value = 19780503);
-    template<class In> void seed(In& first, In last);
-    result_type min() const;
-    result_type max() const;
-    result_type operator()();
-  };
-  template<class RealType, int w, int s, int r>
-  bool operator==(const subtract_with_carry_01<RealType, w, s, r> x,
-                  const subtract_with_carry_01<RealType, w, s, r> y);
-
-  template<class RealType, int w, int s, int r>
-  bool operator!=(const subtract_with_carry_01<RealType, w, s, r> x,
-                  const subtract_with_carry_01<RealType, w, s, r> y);
-
-  template<class CharT, class Traits,
-           class RealType, int w, int s, int r>
-  std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& os,
-                                               const subtract_with_carry_01<RealType, w, s, r>& f);
-
-  template<class CharT, class Traits,
-           class RealType, int w, int s, int r>
-  std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& is, 
-                                               subtract_with_carry_01<RealType, w, s, r>& f);
-}
-
- -The following relation shall hold: 0<s<r. -

- -The size of the state is r. - -

    subtract_with_carry_01()
-Effects: Constructs a subtract_with_carry_01 -engine and invokes seed(). - -
    explicit subtract_with_carry_01(unsigned int value)
-Effects: Constructs a subtract_with_carry_01 -engine and invokes seed(value). - -
    template<class In> subtract_with_carry_01(In& first, In last)
-Effects: Constructs a subtract_with_carry_01 -engine and invokes seed(first, last). - -
    void seed(unsigned int value = 19780503)
-Effects: With a linear congruential generator l(i) -having parameters m = 2147483563, a = 40014, c = 0, and l(0) = -value, sets x(-r) ... x(-1) to (l(1)*2-w) mod 1 -... (l(r)*2-w) mod 1, respectively. If x(-1) == 0, sets -carry(-1) = 2-w, else sets carry(-1) = 0. -
-Complexity: O(r) - -
    template<class In> void seed(In& first, In last)
-Effects: With n=w/32+1 (rounded downward) and given -the values z0 ... zn*r-1 obtained by -dereferencing [first, first+n*r), sets x(-r) ... x(-1) to -(z0 * 232 + ... + zn-1 * -232*(n-1)) * 2-w mod 1 ... (z(r-1)*n -* 232 + ... + zr-1 * 232*(n-1)) * -2-w mod 1. If x(-1) == 0, sets carry(-1) = 2-w, -else sets carry(-1) = 0. -
-Complexity: O(r*n) - -
-    template<class RealType, int w, int s, int r>
-    bool operator==(const subtract_with_carry<RealType, w, s, r> x,
-                    const subtract_with_carry<RealType, w, s, r> y);
-
-Returns: true, if and only if x(i-r) == y(j-r) and -... and x(i-1) == y(j-1). -
-Complexity: O(r) - -
-    template<class CharT, class Traits,
-             class RealType, int w, int s, int r>
-    std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& os,
-                                                 const subtract_with_carry<RealType, w, s, r>& f);
-
-Effects: Write x(i-r)*2w -... x(i-1)*2w, carry(i-1)*2w to os, -in that order. -
-Complexity: O(r) - - -

Class template discard_block

- -A discard_block engine produces random numbers from some -base engine by discarding blocks of data. -

- -

-namespace std {
-  template<class UniformRandomNumberGenerator, int p, int r>
-  class discard_block
-  {
-  public:
-    // types
-    typedef UniformRandomNumberGenerator base_type;
-    typedef typename base_type::result_type result_type;
-  
-    // parameter values
-    static const int block_size = p;
-    static const int used_block = r;
-  
-    //  constructors and member function
-    discard_block();
-    explicit discard_block(const base_type & rng);
-    template<class In> discard_block(In& first, In last);
-    void seed();
-    template<class In> void seed(In& first, In last);
-    const base_type& base() const;
-    result_type min() const;
-    result_type max() const;
-    result_type operator()();  
-  private:
-    // base_type b;                 exposition only
-    // int n;                       exposition only
-  };
-  template<class UniformRandomNumberGenerator, int p, int r>
-  bool operator==(const discard_block<UniformRandomNumberGenerator,p,r> & x,
-                 (const discard_block<UniformRandomNumberGenerator,p,r> & y);
-  template<class UniformRandomNumberGenerator, int p, int r,
-    typename UniformRandomNumberGenerator::result_type val>
-  bool operator!=(const discard_block<UniformRandomNumberGenerator,p,r> & x,
-                 (const discard_block<UniformRandomNumberGenerator,p,r> & y);
-
-  template<class CharT, class traits,
-           class UniformRandomNumberGenerator, int p, int r>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const discard_block<UniformRandomNumberGenerator,p,r> & x);
-  template<class CharT, class traits,
-           class UniformRandomNumberGenerator, int p, int r>
-  basic_istream<CharT, traits>& operator>>(basic_istream<CharT, traits>& is, 
-                                           discard_block<UniformRandomNumberGenerator,p,r> & x);
-
-}
-
- -The template parameter UniformRandomNumberGenerator shall -denote a class that satisfies all the requirements of a uniform random -number generator, given in tables in section x.x. r <= p. The size -of the state is the size of b plus 1. - -
    discard_block()
-Effects: Constructs a discard_block -engine. To construct the subobject b, invokes its default -constructor. Sets n = 0. - -
    explicit discard_block(const base_type & rng)
-Effects: Constructs a discard_block -engine. Initializes b with a copy of rng. -Sets n = 0. - -
    template<class In> discard_block(In& first, In last)
-Effects: Constructs a discard_block -engine. To construct the subobject b, invokes the -b(first, last) constructor. Sets n = 0. - -
    void seed()
-Effects: Invokes b.seed() -and sets n = 0. - -
    template<class In> void seed(In& first, In last)
-Effects: Invokes b.seed(first, -last) and sets n = 0. - -
    const base_type& base() const
-Returns: b - -
    result_type operator()()
-Effects: If n >= r, invokes -b (p-r) times, discards the values returned, -and sets n = 0. In any case, then increments -n and returns b(). - -
-  template<class CharT, class traits,
-           class UniformRandomNumberGenerator, int p, int r>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const discard_block<UniformRandomNumberGenerator,p,r> & x);
-
-Effects: Writes b, then -n to os. - - -

Class template xor_combine

- -A xor_combine engine produces random numbers from two -integer base engines by merging their random values with bitwise -exclusive-or. -

- -

-namespace std {
-  template<class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  class xor_combine
-  {
-  public:
-    // types
-    typedef UniformRandomNumberGenerator1 base1_type;
-    typedef UniformRandomNumberGenerator2 base2_type;
-    typedef typename base_type::result_type result_type;
-  
-    // parameter values
-    static const int shift1 = s1;
-    static const int shift2 = s2;
-  
-    //  constructors and member function
-    xor_combine();
-    xor_combine(const base1_type & rng1, const base2_type & rng2);
-    template<class In> xor_combine(In& first, In last);
-    void seed();
-    template<class In> void seed(In& first, In last);
-    const base1_type& base1() const;
-    const base2_type& base2() const;
-    result_type min() const;
-    result_type max() const;
-    result_type operator()();  
-  private:
-    // base1_type b1;               exposition only
-    // base2_type b2;               exposition only
-  };
-  template<class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  bool operator==(const xor_combine<UniformRandomNumberGenerator1, s1, 
-                                    UniformRandomNumberGenerator2, s2> & x,
-                 (const xor_combine<UniformRandomNumberGenerator1, s1,
-                                    UniformRandomNumberGenerator2, s2> & y);
-  template<class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  bool operator!=(const xor_combine<UniformRandomNumberGenerator1, s1,
-                                    UniformRandomNumberGenerator2, s2> & x,
-                 (const xor_combine<UniformRandomNumberGenerator1, s1,
-                                    UniformRandomNumberGenerator2, s2> & y);
-
-  template<class CharT, class traits,
-           class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const xor_combine<UniformRandomNumberGenerator1, s1,
-                                                             UniformRandomNumberGenerator2, s2> & x);
-  template<class CharT, class traits,
-           class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  basic_istream<CharT, traits>& operator>>(basic_istream<CharT, traits>& is, 
-                                           xor_combine<UniformRandomNumberGenerator1, s1,
-                                                       UniformRandomNumberGenerator2, s2> & x);
-
-}
-
- -The template parameters UniformRandomNumberGenerator1 and -UniformRandomNumberGenerator1 shall denote classes that -satisfy all the requirements of a uniform random number generator, -given in tables in section x.x . The size of the state is -the size of b1 plus the size of -b2. - -
    xor_combine()
-Effects: Constructs a xor_combine -engine. To construct each of the subobjects b1 and -b2, invokes their respective default constructors. - -
    xor_combine(const base1_type & rng1, const base2_type & rng2)
-Effects: Constructs a xor_combine -engine. Initializes b1 with a copy of rng1 and -b2 with a copy of rng2. - -
    template<class In> xor_combine(In& first, In last)
-Effects: Constructs a xor_combine -engine. To construct the subobject b1, invokes the -b1(first, last) constructor. Then, to construct the -subobject b2, invokes the b2(first, last) -constructor. - -
    void seed()
-Effects: Invokes b1.seed() -and b2.seed(). - -
    template<class In> void seed(In& first, In last)
-Effects: Invokes b1.seed(first, -last), then invokes b2.seed(first, last). - -
    const base1_type& base1() const
-Returns: b1 - -
    const base2_type& base2() const
-Returns: b2 - -
    result_type operator()()
-Returns: (b1() << s1) ^ -(b2() << s2). - -
-  template<class CharT, class traits,
-           class UniformRandomNumberGenerator1, int s1,
-           class UniformRandomNumberGenerator2, int s2>
-  basic_ostream<CharT, traits>& operator<<(basic_ostream<CharT, traits>& os,
-                                           const xor_combine<UniformRandomNumberGenerator1, s1,
-                                                             UniformRandomNumberGenerator2, s2> & x);
-
-Effects: Writes b1, then -b2 to os. - - -

Engines with predefined parameters

- -
-namespace std {
-  typedef linear_congruential</* implementation defined */, 16807, 0, 2147483647> minstd_rand0;
-  typedef linear_congruential</* implementation defined */, 48271, 0, 2147483647> minstd_rand;
-
-  typedef mersenne_twister</* implementation defined */,32,624,397,31,0x9908b0df,11,7,0x9d2c5680,15,0xefc60000,18> mt19937;
-
-  typedef subtract_with_carry_01 ranlux_base_01;
-  typedef subtract_with_carry_01 ranlux64_base_01;
-
-  typedef discard_block<subtract_with_carry</* implementation defined */, (1<<24), 10, 24>, 223, 24> ranlux3;
-  typedef discard_block<subtract_with_carry</* implementation defined */, (1<<24), 10, 24>, 389, 24> ranlux4;
-
-  typedef discard_block<subtract_with_carry_01<float, 24, 10, 24>, 223, 24> ranlux3_01;
-  typedef discard_block<subtract_with_carry_01<float, 24, 10, 24>, 389, 24> ranlux4_01;
-}
-
- -For a default-constructed minstd_rand0 object, x(10000) = -1043618065. For a default-constructed minstd_rand -object, x(10000) = 399268537. -

- -For a default-constructed mt19937 object, x(10000) = -3346425566. -

- -For a default-constructed ranlux3 object, x(10000) = -5957620. For a default-constructed ranlux4 object, -x(10000) = 8587295. For a default-constructed ranlux3_01 -object, x(10000) = 5957620 * 2-24. For a -default-constructed ranlux4_01 object, x(10000) = 8587295 -* 2-24. - - - - -

Class random_device

- -A random_device produces non-deterministic random -numbers. It satisfies all the requirements of a uniform random number -generator (given in tables in section x.x). Descriptions are provided -here only for operations on the engines that are not described in one -of these tables or for operations where there is additional semantic -information. -

- -If implementation limitations prevent generating non-deterministic -random numbers, the implementation can employ a pseudo-random number -engine. - -

-namespace std {
-  class random_device
-  {
-  public:
-    // types
-    typedef unsigned int result_type;
-
-    // constructors, destructors and member functions
-    explicit random_device(const std::string& token = /* implementation-defined */);
-    result_type min() const;
-    result_type max() const;
-    double entropy() const;
-    result_type operator()();
-  
-  private:
-    random_device(const random_device& );
-    void operator=(const random_device& );
-  };
-}
-
- -
    explicit random_device(const std::string& token = /* implementation-defined */)
-Effects: Constructs a random_device -non-deterministic random number engine. The semantics and default -value of the token parameter are implementation-defined. -[Footnote: The parameter is intended to allow an implementation to -differentiate between different sources of randomness.] -
-Throws: A value of some type derived from -exception if the random_device could not be -initialized. - -
    result_type min() const
-Returns: -numeric_limits<result_type>::min() - -
    result_type max() const
-Returns: -numeric_limits<result_type>::max() - -
    double entropy() const
-Returns: An entropy estimate for the random numbers -returned by operator(), in the range min() to -log2( max()+1). A deterministic random -number generator (e.g. a pseudo-random number engine) has entropy 0. -
-Throws: Nothing. - -
    result_type operator()()
-Returns: A non-deterministic random value, uniformly -distributed between min() and max(), -inclusive. It is implementation-defined how these values are -generated. -
-Throws: A value of some type derived from -exception if a random number could not be obtained. - - -

Random distribution class templates

- -The class templates specified in this section satisfy all the -requirements of a random distribution (given in tables in section -x.x). Descriptions are provided here only for operations on the -distributions that are not described in one of these tables or for -operations where there is additional semantic information. -

- -A template parameter named IntType shall denote a type -that represents an integer number. This type shall meet the -requirements for a numeric type (26.1 [lib.numeric.requirements]), the -binary operators +, -, *, /, % shall be applicable to it, and a -conversion from int shall exist. [Footnote: The -built-in types int and long meet these -requirements.] -

- -Given an object whose type is specified in this subclause, if the -lifetime of the uniform random number generator referred to in the -constructor invocation for that object has ended, any use of that -object is undefined. -

- -No function described in this section throws an exception, unless an -operation on values of IntType or RealType -throws an exception. [Note: Then, the effects are undefined, -see [lib.numeric.requirements]. ] -

- -The algorithms for producing each of the specified distributions are -implementation-defined. - - -

Class template uniform_int

- -A uniform_int random distribution produces integer random -numbers x in the range min <= x <= max, with equal probability. -min and max are the parameters of the distribution. -

- -A uniform_int random distribution satisfies all the -requirements of a uniform random number generator (given in tables in -section x.x). - -

-namespace std {
-  template<class IntType = int>
-  class uniform_int
-  {
-  public:
-    // types
-    typedef IntType input_type;
-    typedef IntType result_type;
-
-    //  constructors and member function
-    explicit uniform_int(IntType min = 0, IntType max = 9);
-    result_type min() const;
-    result_type max() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng, result_type n);
-  };
-}
-
- -
    uniform_int(IntType min = 0, IntType max = 9)
-Requires: min <= max -
-Effects: Constructs a uniform_int -object. min and max are the parameters of -the distribution. - -
    result_type min() const
-Returns: The "min" parameter of the distribution. - -
    result_type max() const
-Returns: The "max" parameter of the distribution. - -
    result_type operator()(UniformRandomNumberGenerator& urng, result_type n)
-Returns: A uniform random number x in the range 0 -<= x < n. [Note: This allows a -variate_generator object with a uniform_int -distribution to be used with std::random_shuffe, see -[lib.alg.random.shuffle]. ] - - -

Class template bernoulli_distribution

- -A bernoulli_distribution random distribution produces -bool values distributed with probabilities p(true) = p -and p(false) = 1-p. p is the parameter of the distribution. - -
-namespace std {
-  template<class RealType = double>
-  class bernoulli_distribution
-  {
-  public:
-    // types
-    typedef int input_type;
-    typedef bool result_type;
-
-    //  constructors and member function
-    explicit bernoulli_distribution(const RealType& p = RealType(0.5));
-    RealType p() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- -
    bernoulli_distribution(const RealType& p = RealType(0.5))
- -Requires: 0 <= p <= 1 -
-Effects: Constructs a -bernoulli_distribution object. p is the -parameter of the distribution. - -
    RealType p() const
-Returns: The "p" parameter of the distribution. - - -

Class template geometric_distribution

- -A geometric_distribution random distribution produces -integer values i >= 1 with p(i) = (1-p) * -pi-1. p is the parameter of the distribution. - -
-namespace std {
-  template<class IntType = int, class RealType = double>
-  class geometric_distribution
-  {
-  public:
-    // types
-    typedef RealType input_type;
-    typedef IntType result_type;
-
-    //  constructors and member function
-    explicit geometric_distribution(const RealType& p = RealType(0.5));
-    RealType p() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- -
    geometric_distribution(const RealType& p = RealType(0.5))
- -Requires: 0 < p < 1 -
-Effects: Constructs a -geometric_distribution object; p is the -parameter of the distribution. - -
   RealType p() const
-Returns: The "p" parameter of the distribution. - - -

Class template poisson_distribution

- -A poisson_distribution random distribution produces -integer values i >= 0 with p(i) = exp(-mean) * -meani / i!. mean is the parameter of the distribution. - -
-namespace std {
-  template<class IntType = int, class RealType = double>
-  class poisson_distribution
-  {
-  public:
-    // types
-    typedef RealType input_type;
-    typedef IntType result_type;
-
-    //  constructors and member function
-    explicit poisson_distribution(const RealType& mean = RealType(1));
-    RealType mean() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- -
    poisson_distribution(const RealType& mean = RealType(1))
- -Requires: mean > 0 -
-Effects: Constructs a -poisson_distribution object; mean is the -parameter of the distribution. - -
   RealType mean() const
-Returns: The "mean" parameter of the distribution. - - -

Class template binomial_distribution

- -A binomial_distribution random distribution produces -integer values i >= 0 with p(i) = (n over i) * -pi * (1-p)t-i. t and p are the parameters of -the distribution. - -
-namespace std {
-  template<class IntType = int, class RealType = double>
-  class binomial_distribution
-  {
-  public:
-    // types
-    typedef /* implementation-defined */ input_type;
-    typedef IntType result_type;
-
-    //  constructors and member function
-    explicit binomial_distribution(IntType t = 1, const RealType& p = RealType(0.5));
-    IntType t() const;
-    RealType p() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- -
    binomial_distribution(IntType t = 1, const RealType& p = RealType(0.5))
- -Requires: 0 <= p <= 1 and t >= 0 -
-Effects: Constructs a -binomial_distribution object; t and -p are the parameters of the distribution. - -
   IntType t() const
-Returns: The "t" parameter of the distribution. - -
   RealType p() const
-Returns: The "p" parameter of the distribution. - - - -

Class template uniform_real

- -A uniform_real random distribution produces -floating-point random numbers x in the range min <= x <= max, -with equal probability. min and max are the parameters of the -distribution. -

- -A uniform_real random distribution satisfies all the -requirements of a uniform random number generator (given in tables in -section x.x). - -

-namespace std {
-  template<class RealType = double>
-  class uniform_real
-  {
-  public:
-    // types
-    typedef RealType input_type;
-    typedef RealType result_type;
-
-    //  constructors and member function
-    explicit uniform_real(RealType min = RealType(0), RealType max = RealType(1));
-    result_type min() const;
-    result_type max() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- -
    uniform_real(RealType min = RealType(0), RealType max = RealType(1))
-Requires: min <= max -
-Effects: Constructs a -uniform_real object; min and -max are the parameters of the distribution. - -
    result_type min() const
-Returns: The "min" parameter of the distribution. - -
    result_type max() const
-Returns: The "max" parameter of the distribution. - - -

Class template exponential_distribution

- -An exponential_distribution random distribution produces -random numbers x > 0 distributed with probability density function -p(x) = lambda * exp(-lambda * x), where lambda is the parameter of the -distribution. - -
-namespace std {
-  template<class RealType = double>
-  class exponential_distribution
-  {
-  public:
-    // types
-    typedef RealType input_type;
-    typedef RealType result_type;
-
-    //  constructors and member function
-    explicit exponential_distribution(const result_type& lambda = result_type(1));
-    RealType lambda() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- -
    exponential_distribution(const result_type& lambda = result_type(1))
-Requires: lambda > 0 -
-Effects: Constructs an -exponential_distribution object with rng as -the reference to the underlying source of random -numbers. lambda is the parameter for the distribution. - -
    RealType lambda() const
-Returns: The "lambda" parameter of the distribution. - - -

Class template normal_distribution

- -A normal_distribution random distribution produces -random numbers x distributed with probability density function -p(x) = 1/sqrt(2*pi*sigma) * exp(- (x-mean)2 / -(2*sigma2) ), where mean and sigma are the parameters of -the distribution. - -
-namespace std {
-  template<class RealType = double>
-  class normal_distribution
-  {
-  public:
-    // types
-    typedef RealType input_type;
-    typedef RealType result_type;
-
-    //  constructors and member function
-    explicit normal_distribution(base_type & rng, const result_type& mean = 0,
-                                 const result_type& sigma = 1);
-    RealType mean() const;
-    RealType sigma() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- - -
-    explicit normal_distribution( const result_type& mean = 0,
-                                 const result_type& sigma = 1);
-
- -Requires: sigma > 0 -
-Effects: Constructs a -normal_distribution object; mean and -sigma are the parameters for the distribution. - -
    RealType mean() const
-Returns: The "mean" parameter of the distribution. - -
    RealType sigma() const
-Returns: The "sigma" parameter of the distribution. - - -

Class template gamma_distribution

- -A gamma_distribution random distribution produces -random numbers x distributed with probability density function -p(x) = 1/Gamma(alpha) * xalpha-1 * exp(-x), where alpha is the -parameter of the distribution. - -
-namespace std {
-  template<class RealType = double>
-  class gamma_distribution
-  {
-  public:
-    // types
-    typedef RealType input_type;
-    typedef RealType result_type;
-
-    //  constructors and member function
-    explicit gamma_distribution(const result_type& alpha = result_type(1));
-    RealType alpha() const;
-    void reset();
-    template<class UniformRandomNumberGenerator>
-    result_type operator()(UniformRandomNumberGenerator& urng);
-  };
-}
-
- - -
-    explicit gamma_distribution(const result_type& alpha = result_type(1));
-
- -Requires: alpha > 0 -
-Effects: Constructs a -gamma_distribution object; alpha is the -parameter for the distribution. - -
    RealType alpha() const
-Returns: The "alpha" parameter of the distribution. - - - -

V. Acknowledgements

- -
    -
  • Thanks to Walter Brown, Mark Fischler and Marc Paterno from Fermilab -for input about the requirements of high-energy physics. -
  • - -
  • Thanks to David Abrahams for additional comments on the -design.
  • - -
  • Thanks to the Boost community for a platform for experimentation. -
  • - -
- - - -

VI. References

- -