/** * \file LeadingZeros.hpp * \brief Header for LeadingZeros * * Count the leading zeros in a real number. * * Copyright (c) Charles Karney (2006-2011) and licensed * under the MIT/X11 License. For more information, see * http://randomlib.sourceforge.net/ **********************************************************************/ #if !defined(RANDOMLIB_LEADINGZEROS_HPP) #define RANDOMLIB_LEADINGZEROS_HPP 1 namespace RandomLib { /** * \brief Count of leading zeros. * * Count of leading zero bits after the binary point in a real number * uniformly distributed in (0,1). (This is equivalent to the geometric * distribution with probability 1/2.) For example * \code #include RandomLib::Random r; // A RandomGenerator works here too std::cout << "Seed set to " << r.SeedString() << "\n"; LeadingZeros zeros; std::cout << "Count of leading zeros:"; for (size_t i = 0; i < 20; ++i) std::cout << " " << zeros(r); std::cout << "\n"; \endcode **********************************************************************/ class LeadingZeros { public: /** * Return the number of zero bits after the binary point in a real number * uniformly distributed in (0,1). Thus \e k is returned with probability * 1/2k+1. Because MT19937 is \e not a perfect random * number generator, this always returns a result in [0, 19937). * * @tparam Random the type of the random generator. * @param[in,out] r a random generator. * @return the random sample. **********************************************************************/ template unsigned operator()(Random& r) const throw(); }; template unsigned LeadingZeros::operator()(Random& r) const throw() { // It's simpler to count the number of trailing ones in each w-bit block // stopping when we get to a zero bit. // // Process a word in chunks of size m. The algorithm here can deal with // any m assuming that z is modified accordingly. m = 4 is an approximate // optimum. // // Can also adapt this routine to use RandomNumber::highest_bit_idx // instead. However the result is considerably slower. const int m = 4; STATIC_ASSERT(m <= Random::width, "LeadingZeros: m too large"); // mask with m low bits set const typename Random::result_type mask = ~(Random::max << m); // Number of trailing 1 bits in [0, 1<>= m; // shift out the chunk we've processed } // x is all ones (prob 1/2^w); process the next word. return Random::width + operator()(r); } } // namespace RandomLib #endif // RANDOMLIB_LEADINGZEROS_HPP