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