random123

Counter-based Random Number Generators
git clone git://git.meso-star.com/random123.git
Log | Files | Refs | README | LICENSE

MicroURNG.hpp (5332B)


      1 /*
      2 Copyright 2010-2011, D. E. Shaw Research.
      3 All rights reserved.
      4 
      5 Redistribution and use in source and binary forms, with or without
      6 modification, are permitted provided that the following conditions are
      7 met:
      8 
      9 * Redistributions of source code must retain the above copyright
     10   notice, this list of conditions, and the following disclaimer.
     11 
     12 * Redistributions in binary form must reproduce the above copyright
     13   notice, this list of conditions, and the following disclaimer in the
     14   documentation and/or other materials provided with the distribution.
     15 
     16 * Neither the name of D. E. Shaw Research nor the names of its
     17   contributors may be used to endorse or promote products derived from
     18   this software without specific prior written permission.
     19 
     20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 */
     32 #ifndef __MicroURNG_dot_hpp__
     33 #define __MicroURNG_dot_hpp__
     34 
     35 #include <stdexcept>
     36 #include <limits>
     37 
     38 namespace r123{
     39 /**
     40     Given a CBRNG whose ctr_type has an unsigned integral value_type,
     41     MicroURNG<CBRNG>(c, k) is a type that satisfies the
     42     requirements of a C++11 Uniform Random Number Generator.
     43 
     44     The intended purpose is for a MicroURNG to be passed
     45     as an argument to a C++11 Distribution, e.g.,
     46     std::normal_distribution.  See examples/MicroURNG.cpp.
     47 
     48     The MicroURNG functor has a period of "only"
     49 
     50        ctr_type.size()*2^32,
     51 
     52     after which it will silently repeat.
     53 
     54     The high 32 bits of the highest word in the counter c, passed to
     55     the constructor must be zero.  MicroURNG uses these bits to
     56     "count".
     57 
     58     Older versions of the library permitted a second template
     59     parameter by which the caller could control the number of
     60     bits devoted to the URNG's internal counter.  This flexibility
     61     has been disabled because URNGs created with different
     62     numbers of counter bits could, conceivably "collide".
     63 
     64 \code
     65        typedef ?someCBRNG? RNG;
     66        RNG::ctr_type c = ...; // under application control
     67        RNG::key_type k = ...; // 
     68        std::normal_distribution<float> nd;
     69        MicroURNG<RNG> urng(c, k);
     70        for(???){
     71          ...
     72          nd(urng);  // may be called several hundred times with BITS=10
     73          ...
     74        }
     75 \endcode
     76 */
     77 
     78 template<typename CBRNG>
     79 class MicroURNG{
     80     // According to C++11, a URNG requires only a result_type,
     81     // operator()(), min() and max() methods.  Everything else
     82     // (ctr_type, key_type, reset() method, etc.) is "value added"
     83     // for the benefit of users that "know" that they're dealing with
     84     // a MicroURNG.
     85 public:
     86     typedef CBRNG cbrng_type;
     87     static const int BITS = 32;
     88     typedef typename cbrng_type::ctr_type ctr_type;
     89     typedef typename cbrng_type::key_type key_type;
     90     typedef typename cbrng_type::ukey_type ukey_type;
     91     typedef typename ctr_type::value_type result_type;
     92 
     93     R123_STATIC_ASSERT( std::numeric_limits<result_type>::digits >= BITS, "The result_type must have at least 32 bits" );
     94 
     95     result_type operator()(){
     96         if(last_elem == 0){
     97             // jam n into the high bits of c
     98             const size_t W = std::numeric_limits<result_type>::digits;
     99             ctr_type c = c0;
    100             c[c0.size()-1] |= n<<(W-BITS);
    101             rdata = b(c,k);
    102             n++;
    103             last_elem = rdata.size();
    104         }
    105         return rdata[--last_elem];
    106     }
    107     MicroURNG(cbrng_type _b, ctr_type _c0, ukey_type _uk) : b(_b), c0(_c0), k(_uk), n(0), last_elem(0) {
    108         chkhighbits();
    109     }
    110     MicroURNG(ctr_type _c0, ukey_type _uk) : b(), c0(_c0), k(_uk), n(0), last_elem(0) {
    111         chkhighbits();
    112     }
    113 
    114     // _Min and _Max work around a bug in the library shipped with MacOS Xcode 4.5.2.
    115     // See the commment in conventional/Engine.hpp.  
    116     const static result_type _Min = 0;
    117     const static result_type _Max = ~((result_type)0);
    118 
    119     static R123_CONSTEXPR result_type min R123_NO_MACRO_SUBST () { return _Min; }
    120     static R123_CONSTEXPR result_type max R123_NO_MACRO_SUBST () { return _Max; }
    121     // extra methods:
    122     const ctr_type& counter() const{ return c0; }
    123     void reset(ctr_type _c0, ukey_type _uk){
    124         c0 = _c0;
    125         chkhighbits();
    126         k = _uk;
    127         n = 0;
    128         last_elem = 0;
    129     }
    130 
    131 private:
    132     cbrng_type b;
    133     ctr_type c0;
    134     key_type k;
    135     R123_ULONG_LONG n;
    136     size_t last_elem;
    137     ctr_type rdata;
    138     void chkhighbits(){
    139         result_type r = c0[c0.size()-1];
    140         result_type mask = ((uint64_t)std::numeric_limits<result_type>::max R123_NO_MACRO_SUBST ())>>BITS;
    141         if((r&mask) != r)
    142             throw std::runtime_error("MicroURNG: c0, does not have high bits clear");
    143     }
    144 };
    145 } // namespace r123
    146 #endif