123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- /* boost random_speed.cpp performance measurements
- *
- * Copyright Jens Maurer 2000
- * Distributed under the Boost Software License, Version 1.0. (See
- * accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * $Id$
- */
- #include <iostream>
- #include <cstdlib>
- #include <string>
- #include <boost/config.hpp>
- #include <boost/random.hpp>
- #include <boost/progress.hpp>
- #include <boost/shared_ptr.hpp>
- /*
- * Configuration Section
- */
- // define if your C library supports the non-standard drand48 family
- //#define HAVE_DRAND48
- // define if you have the original mt19937int.c (with commented out main())
- #undef HAVE_MT19937INT_C
- // define if you have the original mt19937ar.c (with commented out main())
- // #define HAVE_MT19937AR_C
- // set to your CPU frequency
- static const double cpu_frequency = 1.87 * 1e9;
- /*
- * End of Configuration Section
- */
- /*
- * General portability note:
- * MSVC mis-compiles explicit function template instantiations.
- * For example, f<A>() and f<B>() are both compiled to call f<A>().
- * 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 IntType>
- 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<result_type>::max)(); }
- private:
- int _x;
- };
- // decoration of variate_generator to make it runtime-exchangeable
- // for speed comparison
- template<class Ret>
- class RandomGenBase
- {
- public:
- virtual Ret operator()() = 0;
- virtual ~RandomGenBase() { }
- };
- template<class URNG, class Dist, class Ret = typename Dist::result_type>
- class DynamicRandomGenerator
- : public RandomGenBase<Ret>
- {
- public:
- DynamicRandomGenerator(URNG& urng, const Dist& d) : _rng(urng, d) { }
- Ret operator()() { return _rng(); }
- private:
- boost::variate_generator<URNG&, Dist> _rng;
- };
- template<class Ret>
- class GenericRandomGenerator
- {
- public:
- typedef Ret result_type;
- GenericRandomGenerator() { };
- void set(boost::shared_ptr<RandomGenBase<Ret> > p) { _p = p; }
- // takes over ownership
- void set(RandomGenBase<Ret> * p) { _p.reset(p); }
- Ret operator()() { return (*_p)(); }
- private:
- boost::shared_ptr<RandomGenBase<Ret> > _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<class RNG>
- 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<class RNG>
- 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<class RNG>
- 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<double> & tmp = rng();
- (void) tmp[0];
- }
- show_elapsed(t.elapsed(), iter, name);
- }
- template<class RNG>
- void run(int iter, const std::string & name, RNG rng)
- {
- std::cout << (RNG::has_fixed_range ? "fixed-range " : "");
- // BCC has trouble with string autoconversion for explicit specializations
-
- // 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);
- }
- #ifdef HAVE_DRAND48
- // requires non-standard C library support for srand48/lrand48
- struct lrand48_ {
- static const bool has_fixed_range = false;
- typedef long result_type;
- lrand48_() {
- using namespace std;
- srand48(1);
- }
- result_type operator()() {
- using namespace std;
- return lrand48();
- }
- };
- #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
- #ifdef HAVE_MT19937AR_C
- extern "C" {
- void init_genrand(unsigned long s);
- unsigned long genrand_int32(void);
- }
- struct mt19937_c {
- static const bool has_fixed_range = false;
- mt19937_c() {
- init_genrand(5489);
- }
- typedef unsigned long result_type;
- result_type operator()() {
- return genrand_int32();
- }
- };
- #endif
- template<class PRNG, class Dist>
- inline boost::variate_generator<PRNG&, Dist> make_gen(PRNG & rng, Dist d)
- {
- return boost::variate_generator<PRNG&, Dist>(rng, d);
- }
- template<class Gen>
- void distrib(int iter, const std::string & name, const Gen &)
- {
- Gen gen;
- timing(make_gen(gen, boost::random::uniform_int_distribution<>(-2, 4)),
- iter, name + " uniform_int");
- timing(make_gen(gen, boost::random::uniform_smallint<>(-2, 4)),
- iter, name + " uniform_smallint");
- timing(make_gen(gen, boost::random::bernoulli_distribution<>(0.5)),
- iter, name + " bernoulli");
- timing(make_gen(gen, boost::random::geometric_distribution<>(0.5)),
- iter, name + " geometric");
- timing(make_gen(gen, boost::random::binomial_distribution<int>(4, 0.8)),
- iter, name + " binomial");
- timing(make_gen(gen, boost::random::negative_binomial_distribution<int>(4, 0.8)),
- iter, name + " negative_binomial");
- timing(make_gen(gen, boost::random::poisson_distribution<>(1)),
- iter, name + " poisson");
- timing(make_gen(gen, boost::random::uniform_real_distribution<>(-5.3, 4.8)),
- iter, name + " uniform_real");
- timing(make_gen(gen, boost::random::uniform_01<>()),
- iter, name + " uniform_01");
- timing(make_gen(gen, boost::random::triangle_distribution<>(1, 2, 7)),
- iter, name + " triangle");
- timing(make_gen(gen, boost::random::exponential_distribution<>(3)),
- iter, name + " exponential");
- timing(make_gen(gen, boost::random::normal_distribution<>()),
- iter, name + " normal polar");
- timing(make_gen(gen, boost::random::lognormal_distribution<>()),
- iter, name + " lognormal");
- timing(make_gen(gen, boost::random::chi_squared_distribution<>(4)),
- iter, name + " chi squared");
- timing(make_gen(gen, boost::random::cauchy_distribution<>()),
- iter, name + " cauchy");
- timing(make_gen(gen, boost::random::fisher_f_distribution<>(4, 5)),
- iter, name + " fisher f");
- timing(make_gen(gen, boost::random::student_t_distribution<>(7)),
- iter, name + " student t");
- timing(make_gen(gen, boost::random::gamma_distribution<>(2.8)),
- iter, name + " gamma");
- timing(make_gen(gen, boost::random::weibull_distribution<>(3)),
- iter, name + " weibull");
- timing(make_gen(gen, boost::random::extreme_value_distribution<>()),
- iter, name + " extreme value");
- timing_sphere(make_gen(gen, boost::random::uniform_on_sphere<>(3)),
- iter/10, name + " uniform_on_sphere");
- }
- 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<boost::uint64_t>
- 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", lrand48_()); // coded for lrand48()
- #endif
- run(iter, "minstd_rand0", boost::minstd_rand0());
- run(iter, "minstd_rand", boost::minstd_rand());
- run(iter, "ecuyer combined", boost::ecuyer1988());
- run(iter, "kreutzer1986", boost::kreutzer1986());
- run(iter, "taus88", boost::taus88());
- run(iter, "knuth_b", boost::random::knuth_b());
- run(iter, "hellekalek1995 (inversive)", boost::hellekalek1995());
- run(iter, "mt11213b", boost::mt11213b());
- run(iter, "mt19937", boost::mt19937());
- #if !defined(BOOST_NO_INT64_T)
- run(iter, "mt19937_64", boost::mt19937_64());
- #endif
- run(iter, "lagged_fibonacci607", boost::lagged_fibonacci607());
- run(iter, "lagged_fibonacci1279", boost::lagged_fibonacci1279());
- run(iter, "lagged_fibonacci2281", boost::lagged_fibonacci2281());
- run(iter, "lagged_fibonacci3217", boost::lagged_fibonacci3217());
- run(iter, "lagged_fibonacci4423", boost::lagged_fibonacci4423());
- run(iter, "lagged_fibonacci9689", boost::lagged_fibonacci9689());
- run(iter, "lagged_fibonacci19937", boost::lagged_fibonacci19937());
- run(iter, "lagged_fibonacci23209", boost::lagged_fibonacci23209());
- run(iter, "lagged_fibonacci44497", boost::lagged_fibonacci44497());
- 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, "ranlux64_3", boost::ranlux3());
- run(iter, "ranlux64_4", boost::ranlux4());
- run(iter, "ranlux64_3_01", boost::ranlux3_01());
- run(iter, "ranlux64_4_01", boost::ranlux4_01());
- run(iter, "ranlux24", boost::ranlux3());
- run(iter, "ranlux48", boost::ranlux4());
- run(iter, "counting", counting());
- #ifdef HAVE_MT19937INT_C
- // requires the original mt19937int.c
- run<float>(iter, "mt19937 original"); // coded for sgenrand()/genrand()
- #endif
- #ifdef HAVE_MT19937AR_C
- run(iter, "mt19937ar.c", mt19937_c());
- #endif
- distrib(iter, "counting", counting());
- distrib(iter, "minstd_rand", boost::minstd_rand());
- distrib(iter, "kreutzer1986", boost::kreutzer1986());
- distrib(iter, "mt19937", boost::mt19937());
-
- distrib(iter, "lagged_fibonacci607", boost::lagged_fibonacci607());
- }
|