RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
LeadingZeros.hpp
Go to the documentation of this file.
1 /**
2  * \file LeadingZeros.hpp
3  * \brief Header for LeadingZeros
4  *
5  * Count the leading zeros in a real number.
6  *
7  * Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
8  * under the MIT/X11 License. For more information, see
9  * http://randomlib.sourceforge.net/
10  **********************************************************************/
11 
12 #if !defined(RANDOMLIB_LEADINGZEROS_HPP)
13 #define RANDOMLIB_LEADINGZEROS_HPP 1
14 
15 namespace RandomLib {
16  /**
17  * \brief Count of leading zeros.
18  *
19  * Count of leading zero bits after the binary point in a real number
20  * uniformly distributed in (0,1). (This is equivalent to the geometric
21  * distribution with probability 1/2.) For example
22  * \code
23  #include <RandomLib/LeadingZeros.hpp>
24 
25  RandomLib::Random r; // A RandomGenerator works here too
26  std::cout << "Seed set to " << r.SeedString() << "\n";
27  LeadingZeros zeros;
28  std::cout << "Count of leading zeros:";
29  for (size_t i = 0; i < 20; ++i)
30  std::cout << " " << zeros(r);
31  std::cout << "\n";
32  \endcode
33  **********************************************************************/
34  class LeadingZeros {
35  public:
36  /**
37  * Return the number of zero bits after the binary point in a real number
38  * uniformly distributed in (0,1). Thus \e k is returned with probability
39  * 1/2<sup><i>k</i>+1</sup>. Because MT19937 is \e not a perfect random
40  * number generator, this always returns a result in [0, 19937).
41  *
42  * @tparam Random the type of the random generator.
43  * @param[in,out] r a random generator.
44  * @return the random sample.
45  **********************************************************************/
46  template<class Random> unsigned operator()(Random& r) const throw();
47  };
48 
49  template<class Random>
50  unsigned LeadingZeros::operator()(Random& r) const throw() {
51  // It's simpler to count the number of trailing ones in each w-bit block
52  // stopping when we get to a zero bit.
53  //
54  // Process a word in chunks of size m. The algorithm here can deal with
55  // any m assuming that z is modified accordingly. m = 4 is an approximate
56  // optimum.
57  //
58  // Can also adapt this routine to use RandomNumber::highest_bit_idx
59  // instead. However the result is considerably slower.
60  const int m = 4;
61  STATIC_ASSERT(m <= Random::width, "LeadingZeros: m too large");
62  // mask with m low bits set
63  const typename Random::result_type mask = ~(Random::max << m);
64  // Number of trailing 1 bits in [0, 1<<m). However, correct results are
65  // also obtained with any permutation of this array. This particular
66  // permutation is useful since the initial 1/2, 1/4, etc. can be used for
67  // m-1, m-2, etc. To generate the array for the next higher m, append a
68  // duplicate of the array and increment the last entry by one.
69  const unsigned z[1 << m] =
70  { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, };
71  typename Random::result_type x = r();
72  for (unsigned b = m, n = 0; b < Random::width; b += m) {
73  n += z[x & mask]; // count trailing 1s in chunk
74  if (n < b) // chunk contains a 0
75  return n;
76  x >>= m; // shift out the chunk we've processed
77  }
78  // x is all ones (prob 1/2^w); process the next word.
79  return Random::width + operator()(r);
80  }
81 
82 } // namespace RandomLib
83 
84 #endif // RANDOMLIB_LEADINGZEROS_HPP
Generate random integers, reals, and booleans.
Count of leading zeros.
unsigned operator()(Random &r) const
#define STATIC_ASSERT(cond, reason)
Definition: MPFRRandom.hpp:31
Generator::result_type result_type