random123

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

ut_uniform.cpp (5947B)


      1 /*
      2 Copyright 2013, 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 
     33  /* ut_uniform.cpp:   unit test for uniform.hpp.  
     34 
     35     This is a "sanity test" of u01, uneg11 and u01fixedpt.  We confirm
     36     that a histogram of few thousand calls to each of the functions
     37     matches a reference histogram.  This verifies that the results are
     38     generally sane i.e., they fall within the expected range, and that
     39     they are close to a correct distribution.  It is *not* a foolproof
     40     test of correctness, but it should catch portability issues
     41     like errors in r123::make_signed or r123::make_unsigned
     42     or r123::maxTvalue or misunderstandings about std::numeric_limits.
     43 
     44     There is a "known answer test" for uniform.hpp in ut_uniform_IEEEkat.cpp,
     45     but it is only expected to work on machines with strict IEEE arithmetic
     46     and  no high-precicision intermediates.  See its own comments for
     47     more details.
     48  */
     49 
     50 #include <Random123/uniform.hpp>
     51 #include <Random123/threefry.h>
     52 #include <stdio.h>
     53 #include <stdlib.h>
     54 #include <map>
     55 #include <string>
     56 #include <sstream>
     57 
     58 using namespace r123;
     59 
     60 template <typename T>
     61 typename r123::make_unsigned<T>::type U(T x){ return x; }
     62 
     63 template <typename T>
     64 typename r123::make_signed<T>::type S(T x){ return x; }
     65         
     66 #define Chk(u, Rng, Ftype) do{                            \
     67         chk<Ftype, Rng>(#u, #Rng, #Ftype, &u<Ftype, Rng::ctr_type::value_type>); \
     68     }while(0)
     69 
     70 std::map<std::string, std::string> refmap;
     71 
     72 void RefHist(const char* k, const char *v){
     73     refmap[std::string(k)] = std::string(v);
     74 }
     75 
     76 void fillrefhist(){
     77 #include "ut_uniform_reference.hpp"
     78 }
     79 
     80 bool checking = true;
     81 int nfail = 0;
     82 
     83 template<typename Ftype, typename RNG, typename Utype>
     84 void chk(const std::string& fname, const std::string& rngname, const std::string& ftypename, Utype f){
     85     std::string key = fname + " " + rngname + " " + ftypename;
     86     RNG rng;
     87     typedef typename RNG::ukey_type ukey_type;
     88     typedef typename RNG::ctr_type ctr_type;
     89     typedef typename RNG::key_type key_type;
     90 
     91     ctr_type c = {{}};
     92     ukey_type uk = {{}};
     93     key_type k = uk;
     94     // 26 bins - 13 greater than 0 and 13 less.  Why 13?  Because a
     95     // prime number seems less likely to tickle the rounding-related
     96     // corner cases, which is aruably both good and bad.
     97     const int NBINS=26;
     98     
     99     int hist[NBINS] = {};
    100     for(int i=0; i<1000; ++i){
    101         c = c.incr();
    102         ctr_type r = rng(c, k);
    103         for(int j=0; j<ctr_type::static_size; ++j){
    104             Ftype u = f(r[j]);
    105             //printf("%s %llx, %.17g\n", key.c_str(), (long long)r[j], (double)u);
    106             R123_ASSERT( u >= -1.);
    107             R123_ASSERT( u <= 1.);
    108             int idx = (int) ((u + Ftype(1.))*Ftype(NBINS/2));
    109             hist[idx]++;
    110         }
    111     }
    112     std::ostringstream oss;
    113     for(int i=0; i<NBINS; ++i){
    114         oss << " " << hist[i];
    115     }
    116     if(checking){
    117         if( oss.str() != refmap[key] ){
    118             printf("MISMATCH:  %s:\n\tcomputed histogram=%s\n\treference histogram=%s\n", 
    119                    key.c_str(),
    120                    oss.str().c_str(),
    121                    refmap[key].c_str());
    122             nfail++;
    123         }
    124     }else{
    125         printf("RefHist(\"%s\", \"%s\");\n",  key.c_str(), oss.str().c_str());
    126     }
    127 }
    128 
    129 int main(int argc, char **argv){
    130     checking = (argc==1);
    131     fillrefhist();
    132 
    133     // 18 tests:  3 functions (u01, uneg11, u01fixedpt)
    134     //          x 2 input sizes (32 bit or 64 bit)
    135     //          x 3 output sizes (float, double, long double)
    136     Chk(u01, Threefry4x32, float);
    137     Chk(u01, Threefry4x32, double);
    138     Chk(u01, Threefry4x32, long double);
    139 
    140 #if R123_USE_64BIT
    141     Chk(u01, Threefry4x64, float);
    142     Chk(u01, Threefry4x64, double);
    143     Chk(u01, Threefry4x64, long double);
    144 #endif
    145 
    146     Chk(uneg11, Threefry4x32, float);
    147     Chk(uneg11, Threefry4x32, double);
    148     Chk(uneg11, Threefry4x32, long double);
    149 
    150 #if R123_USE_64BIT
    151     Chk(uneg11, Threefry4x64, float);
    152     Chk(uneg11, Threefry4x64, double);
    153     Chk(uneg11, Threefry4x64, long double);
    154 #endif
    155     
    156     Chk(u01fixedpt, Threefry4x32, float);
    157     Chk(u01fixedpt, Threefry4x32, double);
    158     Chk(u01fixedpt, Threefry4x32, long double);
    159 
    160 #if R123_USE_64BIT
    161     Chk(u01fixedpt, Threefry4x64, float);
    162     Chk(u01fixedpt, Threefry4x64, double);
    163     Chk(u01fixedpt, Threefry4x64, long double);
    164 #endif
    165 
    166     if(nfail){
    167         printf("// %s: FAILED %d Known-Answer-Tests failed\n", argv[0], nfail);
    168     }else if(checking){
    169         printf("%s: SUCCESS\n", argv[0]);
    170     }
    171 
    172     return !!nfail;
    173 }