RandomNumber.hpp
Go to the documentation of this file.
00001 /**
00002  * \file RandomNumber.hpp
00003  * \brief Header for RandomNumber
00004  *
00005  * Infinite precision random numbers.
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(RANDOMNUMBER_HPP)
00012 #define RANDOMNUMBER_HPP "$Id: RandomNumber.hpp 6723 2010-01-11 14:20:10Z ckarney $"
00013 
00014 #include <vector>
00015 #include <iomanip>
00016 #include <limits>
00017 #include <cmath>                // for std::pow
00018 
00019 #if !defined(STATIC_ASSERT)
00020 /**
00021  * A simple compile-time assert.
00022  **********************************************************************/
00023 #define STATIC_ASSERT(cond,reason) { enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; }
00024 #endif
00025 
00026 namespace RandomLib {
00027   /**
00028    * \brief Infinite precision random numbers.
00029    *
00030    * Implement infinite precision random numbers.  Integer part is non-random.
00031    * Fraction part consists of any some number of digits in base
00032    * 2<sup><i>b</i></sup>.  If \e m digits have been generated then the
00033    * fraction is uniformly distributed in the open interval
00034    * sum<sub><i>k</i>=1</sub><sup><i>m</i></sup>
00035    * <i>f</i><sub><i>k</i>-1</sub>/2<sup><i>kb</i></sup> +
00036    * (0,1)/2<sup><i>mb</i></sup>.  When a RandomNumber is first constructed the
00037    * integer part is zero and \e m = 0, and the number represents (0,1).  A
00038    * vRandomNumber is able to represent all numbers in the symmetric open
00039    * interval (-2<sup>31</sup>, 2<sup>31</sup>).  In this implementation \a b
00040    * must be less than 4 or a multiple of 4.  (This restriction allows printing
00041    * in hexadecimal and can easily be relaxed.  There's also no essential
00042    * reason why the base should be a power of 2.)
00043    **********************************************************************/
00044   template<int bits = 1> class RandomNumber {
00045   public:
00046     /**
00047      * Constructor sets number to \a n + (0,1).
00048      **********************************************************************/
00049     RandomNumber(int n = 0) : _n(n) {};
00050     /**
00051      * Return integer part of RandomNumber.
00052      **********************************************************************/
00053     int Integer() const { return _n; }
00054     /**
00055      * Return digit number \a k, generating it if necesary.
00056      **********************************************************************/
00057     template<class Random> unsigned Digit(Random& r, unsigned k) {
00058       ExpandTo(r, k + 1);
00059       return _f[k];
00060     }
00061     /**
00062      * Return digit number \a k, without generating new digits.
00063      **********************************************************************/
00064     unsigned RawDigit(unsigned k) const {
00065       return _f.at(k);
00066     }
00067     /**
00068      * Add integer \a k to RandomNumber
00069      **********************************************************************/
00070     void AddInteger(int k) { _n += k; }
00071     /**
00072      * Set integer part of RandomNumber \a k
00073      **********************************************************************/
00074     void SetInteger(int k) { _n = k; }
00075     /**
00076      * Return to initial state, uniformly distributed in \a n + (0,1).
00077      **********************************************************************/
00078     void Init(int n = 0) {
00079       STATIC_ASSERT(bits > 0 && bits <= w && (bits < 4 || bits % 4 == 0),
00080                     "RandomNumber: unsupported value for bits");
00081       _n = n;
00082       _f.clear();
00083     }
00084     /**
00085      * Compare two RandomNumbers, *this < \a t
00086      **********************************************************************/
00087     template<class Random> bool LessThan(Random& r, RandomNumber& t) {
00088       if (this == &t)
00089         return false;           // same object
00090       if (_n < t._n)
00091         return true;
00092       else if (_n > t._n)
00093         return false;
00094       for (size_t k = 0; ; ++k) {
00095         // Impose an order on the evaluation of the digits.
00096         const unsigned x = Digit(r,k);
00097         const unsigned y = t.Digit(r,k);
00098         if (x == y)
00099           continue; // Two distinct numbers are never equal
00100         return x < y;
00101       }
00102     }
00103     /**
00104      * Change sign of a RandomNumber
00105      **********************************************************************/
00106     void Negate() {
00107       const unsigned mask = bits == w ? ~0U : ~(~0U << (bits < w ? bits : 0));
00108       for (size_t k = 0; k < Size(); ++k)
00109         _f[k] = ~_f[k] & mask;
00110       // Need the -1 shift because the fraction part is always positive
00111       _n = - _n - 1;
00112     }
00113     /**
00114      * Return the number of digits in fraction
00115      **********************************************************************/
00116     size_t Size() const {
00117       return _f.size();
00118     }
00119     /**
00120      * Return the fraction part of the RandomNumber as a floating point number
00121      * of type RealType rounded to the nearest multiple of
00122      * 1/2<sup><i>p</i></sup>, where \e p =
00123      * std::numeric_limits<RealType>::digits, and, if necessary, creating
00124      * additional digits of the number.
00125      **********************************************************************/
00126     template<typename RealType, typename Random> RealType Fraction(Random& r) {
00127       STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
00128                     "RandomNumber::Fraction: invalid real type RealType");
00129       const int d = std::numeric_limits<RealType>::digits;
00130       const int k = (d + bits - 1)/bits;
00131       const int kg = (d + bits)/bits;   // For guard bit
00132       RealType y = 0;
00133       if (Digit(r, kg - 1) & (1U << (kg * bits - d - 1)))
00134         // if guard bit is set, round up.
00135         y += std::pow(RealType(2), -d);
00136       const RealType fact = std::pow(RealType(2), -bits);
00137       RealType mult = RealType(1);
00138       for (size_t i = 0; i < k; ++i) {
00139         mult *= fact;
00140         y += mult * RealType(i < k - 1 ? RawDigit(i) :
00141                       RawDigit(i) & (~0U << (k * bits - d)));
00142       }
00143       return y;
00144     }
00145     /**
00146      * Return the value of the RandomNumber rounded to nearest floating point
00147      * number of type RealType and, if necessary, creating additional digits of
00148      * the number.
00149      **********************************************************************/
00150     template<typename RealType, class Random> RealType Value(Random& r) {
00151       // Ignore the possibility of overflow here (OK because int doesn't
00152       // currently overflow any real type).  Assume the real type supports
00153       // denormalized numbers.  Need to treat rounding explicitly since the
00154       // missing digits always imply rounding up.
00155       STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
00156                     "RandomNumber::Value: invalid real type RealType");
00157       const int digits = std::numeric_limits<RealType>::digits,
00158         min_exp = std::numeric_limits<RealType>::min_exponent;
00159       const bool negative = Integer() < 0;
00160       if (negative)
00161         Negate();
00162       unsigned n = Integer();
00163       int lead;                 // Position of leading bit (0.5 = position 0)
00164       if (n)
00165         lead = highest_bit_idx(n);
00166       else {
00167         int i = 0;
00168         while ( Digit(r, i) == 0 && i < (-min_exp)/bits )
00169           ++i;
00170         lead = highest_bit_idx(RawDigit(i)) - (i + 1) * bits;
00171         // To handle denormalized numbers set lead = max(lead, min_exp)
00172         lead = lead > min_exp ? lead : min_exp;
00173       }
00174       int trail = lead - digits; // Position of guard bit (0.5 = position 0)
00175       RealType y;
00176       if (trail > 0) {
00177         y = RealType(n & (~0U << trail));
00178         if (n & (1U << (trail - 1)))
00179           y += std::pow(RealType(2), trail);
00180       } else {
00181         y = RealType(n);
00182         int k = (-trail)/bits;  // Byte with guard bit
00183         if (Digit(r, k) & (1U << ((k + 1) * bits + trail - 1)))
00184           y += std::pow(RealType(2), trail);
00185         // Byte with trailing bit (can be negative)
00186         k = (-trail - 1 + bits)/bits - 1;
00187         const RealType fact = std::pow(RealType(2), -bits);
00188         RealType mult = RealType(1);
00189         for (int i = 0; i <= k; ++i) {
00190           mult *= fact;
00191           y += mult * RealType(i < k ? RawDigit(i) :
00192                         RawDigit(i) & (~0U << ((k + 1) * bits + trail)));
00193         }
00194       }
00195       if (negative) {
00196         Negate();
00197         y *= -1;
00198       }
00199       return y;
00200     }
00201     /**
00202      * Return the range of possible values for the RandomNumber as pair of
00203      * doubles.  This doesn't create any additional digits of the result and
00204      * doesn't try to control roundoff.
00205      **********************************************************************/
00206     std::pair<double, double> Range() const {
00207       double y = Integer();
00208       const double fact = std::pow(double(2), -bits);
00209       double mult = double(1);
00210       for (size_t i = 0; i < Size(); ++i) {
00211         mult *= fact;
00212         y += mult * RawDigit(i);
00213       }
00214       return std::pair<double, double>(y, y + mult);
00215     }
00216 
00217   private:
00218     /**
00219      * The integer part
00220      **********************************************************************/
00221     int _n;
00222     /**
00223      * The fraction part
00224      **********************************************************************/
00225     std::vector<unsigned> _f;
00226     /**
00227      * Fill RandomNumber to \a k digits.
00228      **********************************************************************/
00229     template<class Random> void ExpandTo(Random& r, size_t k) {
00230       size_t l = _f.size();
00231       if (k <= l)
00232         return;
00233       _f.resize(k);
00234       for (size_t i = l; i < k; ++i)
00235         _f[i] = r.template Integer<bits>();
00236     }
00237     /**
00238      * Return index [0..32] of highest bit set.  Return 0 if x = 0, 32 is if x
00239      * = ~0.  (From Algorithms for programmers by Joerg Arndt.)
00240      **********************************************************************/
00241     static int highest_bit_idx(unsigned x) {
00242       if (x == 0) return 0;
00243       int r = 1;
00244       if (x & 0xffff0000U) { x >>= 16; r += 16; }
00245       if (x & 0x0000ff00U) { x >>=  8; r +=  8; }
00246       if (x & 0x000000f0U) { x >>=  4; r +=  4; }
00247       if (x & 0x0000000cU) { x >>=  2; r +=  2; }
00248       if (x & 0x00000002U) {           r +=  1; }
00249       return r;
00250     }
00251     /**
00252      * The number of bits in unsigned.
00253      **********************************************************************/
00254     static const int w = std::numeric_limits<unsigned>::digits;
00255   };
00256 
00257   /**
00258    * \relates RandomNumber
00259    * Print a RandomNumber.  Format is n.dddd... where the base for printing is
00260    * 2<sup>max(4,<i>b</i>)</sup>.  The ... represents an infinite sequence of
00261    * ungenerated random digits (uniformly distributed).  Thus with \a b = 1,
00262    * 0.0... = (0,1/2), 0.00... = (0,1/4), 0.11... = (3/4,1), etc.
00263    **********************************************************************/
00264   template<int bits> inline
00265   std::ostream& operator<<(std::ostream& os, const RandomNumber<bits>& n) {
00266     const std::ios::fmtflags oldflags = os.flags();
00267     RandomNumber<bits> t = n;
00268     unsigned i;
00269     if (t.Integer() < 0) {
00270       os << "-";
00271       t.Negate();
00272     }
00273     i = unsigned(t.Integer());
00274     os << std::hex  << std::setfill('0');
00275     if (i == 0)
00276       os << "0";
00277     else {
00278       bool first = true;
00279       const int w = std::numeric_limits<unsigned>::digits;
00280       const unsigned mask = bits == w ? ~0U : ~(~0U << (bits < w ? bits : 0));
00281       for (int s = ((w + bits - 1)/bits) * bits - bits; s >= 0; s -= bits) {
00282         unsigned d = mask & (i >> s);
00283         if (d || !first) {
00284           if (first) {
00285             os << d;
00286             first = false;
00287           }
00288           else
00289             os << std::setw((bits+3)/4) << d;
00290         }
00291       }
00292     }
00293     os << ".";
00294     size_t s = t.Size();
00295     for (size_t i = 0; i < s; ++i)
00296       os << std::setw((bits+3)/4) << t.RawDigit(i);
00297     os << "..." << std::setfill(' ');
00298     os.flags(oldflags);
00299     return os;
00300   }
00301 } // namespace RandomLib
00302 #endif  // RANDOMNUMBER_HPP