00001 /** 00002 * \file LeadingZeros.hpp 00003 * \brief Header for LeadingZeros 00004 * 00005 * Count the leading zeros in a real number. 00006 * 00007 * Written by Charles Karney <charles@karney.com> and licensed under the LGPL. 00008 * For more information, see http://randomlib.sourceforge.net/ 00009 **********************************************************************/ 00010 00011 #if !defined(LEADINGZEROS_HPP) 00012 #define LEADINGZEROS_HPP "$Id: LeadingZeros.hpp 6723 2010-01-11 14:20:10Z ckarney $" 00013 00014 namespace RandomLib { 00015 /** 00016 * \brief Count of leading zeros. 00017 * 00018 * Count of leading zero bits after the binary point in a real number 00019 * uniformly distributed in (0,1). (This is equivalent to the geometric 00020 * distribution with probability 1/2.) For example 00021 * \code 00022 * #include "RandomLib/LeadingZeros.hpp" 00023 * 00024 * RandomLib::Random r; // A RandomGenerator works here too 00025 * std::cout << "Seed set to " << r.SeedString() << std::endl; 00026 * LeadingZeros zeros; 00027 * std::cout << "Count of leading zeros:"; 00028 * for (size_t i = 0; i < 20; ++i) 00029 * std::cout << " " << zeros(r); 00030 * std::cout << std::endl; 00031 * \endcode 00032 **********************************************************************/ 00033 class LeadingZeros { 00034 public: 00035 /** 00036 * Return the number of zero bits after the binary point in a real number 00037 * uniformly distributed in (0,1). Thus \e k is returned with probability 00038 * 1/2<sup><i>k</i>+1</sup>. Because MT19937 is \e not a perfect random 00039 * number generator, this always returns a result in [0, 19937). 00040 **********************************************************************/ 00041 template<class Random> unsigned operator()(Random& r) const throw(); 00042 }; 00043 00044 template<class Random> 00045 inline unsigned LeadingZeros::operator()(Random& r) const throw() { 00046 // It's simpler to count the number of trailing ones in each w-bit block 00047 // stopping when we get to a zero bit. 00048 // 00049 // Process a word in chunks of size m. The algorithm here can deal with 00050 // any m assuming that z is modified accordingly. m = 4 is an approximate 00051 // optimum. 00052 // 00053 // Can also adapt this routine to use RandomNumber::highest_bit_idx 00054 // instead. However the result is considerably slower. 00055 const int m = 4; 00056 // mask with m low bits set 00057 const typename Random::result_type mask = ~(Random::max << m); 00058 // Number of trailing 1 bits in [0, 1<<m). However, correct results are 00059 // also obtained with any permutation of this array. This particular 00060 // permutation is useful since the initial 1/2, 1/4, etc. can be used for 00061 // m-1, m-2, etc. To generate the array for the next higher m, append a 00062 // duplicate of the array and increment the last entry by one. 00063 const unsigned z[1 << m] = 00064 { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, }; 00065 typename Random::result_type x = r(); 00066 for (unsigned b = m, n = 0; b < Random::width; b += m) { 00067 n += z[x & mask]; // count trailing 1s in chunk 00068 if (n < b) // chunk contains a 0 00069 return n; 00070 x >>= m; // shift out the chunk we've processed 00071 } 00072 // x is all ones (prob 1/2^w); process the next word. 00073 return Random::width + operator()(r); 00074 } 00075 } // namespace RandomLib 00076 #endif // LEADINGZEROS_HPP