Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

zigrandom.cc

Go to the documentation of this file.
00001 /*! @file
00002 *==========================================================================
00003 *  This code is Copyright (C) 2005, Jurgen A. Doornik.
00004 *  Permission to use this code for non-commercial purposes
00005 *  is hereby given, provided proper reference is made to:
00006 *   Doornik, J.A. (2005), "An Improved Ziggurat Method to Generate Normal
00007 *          Random Samples", mimeo, Nuffield College, University of Oxford,
00008 *     and www.doornik.com/research.
00009 *   or the published version when available.
00010 * This reference is still required when using modified versions of the code.
00011 *  This notice should be maintained in modified versions of the code.
00012 * No warranty is given regarding the correctness of this code.
00013 *==========================================================================
00014 *
00015 * @author Jurgen A. Doornik (Creator)
00016 */
00017 
00018 #include <limits.h>
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <cmath>
00022 
00023 #include "zigrandom.h"
00024 
00025 #ifdef __cplusplus
00026 extern "C" {
00027 #endif
00028   
00029 /*---------------------------- GetInitialSeeds -----------------------------*/
00030 void GetInitialSeeds(unsigned int auiSeed[], int cSeed,
00031   unsigned int uiSeed, unsigned int uiMin)
00032 {
00033   int i;
00034   unsigned int s = uiSeed;                  /* may be 0 */
00035 
00036   for (i = 0; i < cSeed; )
00037   { /* see Knuth p.106, Table 1(16) and Numerical Recipes p.284 (ranqd1)*/
00038     s = 1664525 * s + 1013904223;
00039     if (s <= uiMin)
00040       continue;
00041         auiSeed[i] = s;
00042     ++i;
00043     }
00044 }
00045 /*-------------------------- END GetInitialSeeds ---------------------------*/
00046 
00047 
00048 /*------------------------ George Marsaglia MWC ----------------------------*/
00049 #define MWC_R  256
00050 #define MWC_A  LIT_UINT64(809430660)
00051 #define MWC_AI 809430660
00052 #define MWC_C  362436
00053 static unsigned int s_uiStateMWC = MWC_R - 1;
00054 static unsigned int s_uiCarryMWC = MWC_C;
00055 static unsigned int s_auiStateMWC[MWC_R];
00056 
00057 void RanSetSeed_MWC8222(int *piSeed, int cSeed)
00058 {
00059   s_uiStateMWC = MWC_R - 1;
00060   s_uiCarryMWC = MWC_C;
00061   
00062   if (cSeed == MWC_R)
00063   {
00064     int i;
00065     for (i = 0; i < MWC_R; ++i)
00066     {
00067       s_auiStateMWC[i] = (unsigned int)piSeed[i];
00068     }
00069   }
00070   else
00071   {
00072     GetInitialSeeds(s_auiStateMWC, MWC_R, piSeed && cSeed ? piSeed[0] : 0, 0);
00073   }
00074 }
00075 unsigned int IRan_MWC8222(void)
00076 {
00077   UINT64 t;
00078 
00079   s_uiStateMWC = (s_uiStateMWC + 1) & (MWC_R - 1);
00080   t = MWC_A * s_auiStateMWC[s_uiStateMWC] + s_uiCarryMWC;
00081   s_uiCarryMWC = (unsigned int)(t >> 32);
00082   s_auiStateMWC[s_uiStateMWC] = (unsigned int)t;
00083     return (unsigned int)t;
00084 }
00085 double DRan_MWC8222(void)
00086 {
00087   UINT64 t;
00088 
00089   s_uiStateMWC = (s_uiStateMWC + 1) & (MWC_R - 1);
00090   t = MWC_A * s_auiStateMWC[s_uiStateMWC] + s_uiCarryMWC;
00091   s_uiCarryMWC = (unsigned int)(t >> 32);
00092   s_auiStateMWC[s_uiStateMWC] = (unsigned int)t;
00093   return RANDBL_32new(t);
00094 }
00095 void VecIRan_MWC8222(unsigned int *auiRan, int cRan)
00096 {
00097   UINT64 t;
00098   unsigned int carry = s_uiCarryMWC, status = s_uiStateMWC;
00099   
00100   for (; cRan > 0; --cRan, ++auiRan)
00101   {
00102     status = (status + 1) & (MWC_R - 1);
00103     t = MWC_A * s_auiStateMWC[status] + carry;
00104     *auiRan = s_auiStateMWC[status] = (unsigned int)t;
00105     carry = (unsigned int)(t >> 32);
00106   }
00107   s_uiCarryMWC = carry;
00108   s_uiStateMWC = status;
00109 }
00110 void VecDRan_MWC8222(double *adRan, int cRan)
00111 {
00112   UINT64 t;
00113   unsigned int carry = s_uiCarryMWC, status = s_uiStateMWC;
00114   
00115   for (; cRan > 0; --cRan, ++adRan)
00116   {
00117     status = (status + 1) & (MWC_R - 1);
00118     t = MWC_A * s_auiStateMWC[status] + carry;
00119     s_auiStateMWC[status] = (unsigned int)t;
00120     *adRan = RANDBL_32new(t);
00121     carry = (unsigned int)(t >> 32);
00122   }
00123   s_uiCarryMWC = carry;
00124   s_uiStateMWC = status;
00125 }
00126 /*----------------------- END George Marsaglia MWC -------------------------*/
00127 
00128 
00129 /*------------------- normal random number generators ----------------------*/
00130 static int s_cNormalInStore = 0;         /* > 0 if a normal is in store */
00131 
00132 static DRANFUN s_fnDRanu = DRan_MWC8222;
00133 static IRANFUN s_fnIRanu = IRan_MWC8222;
00134 static IVECRANFUN s_fnVecIRanu = VecIRan_MWC8222;
00135 static DVECRANFUN s_fnVecDRanu = VecDRan_MWC8222;
00136 static RANSETSEEDFUN s_fnRanSetSeed = RanSetSeed_MWC8222;
00137 
00138 double  DRanU(void)
00139 {
00140     return (*s_fnDRanu)();
00141 }
00142 unsigned int IRanU(void)
00143 {
00144     return (*s_fnIRanu)();
00145 }
00146 void RanVecIntU(unsigned int *auiRan, int cRan)
00147 {
00148     (*s_fnVecIRanu)(auiRan, cRan);
00149 }
00150 void RanVecU(double *adRan, int cRan)
00151 {
00152     (*s_fnVecDRanu)(adRan, cRan);
00153 }
00154 //void RanVecU(double *adRan, int cRan)
00155 //{
00156 //  int i, j, c, airan[256];
00157 //
00158 //  for (; cRan > 0; cRan -= 256)
00159 //  {
00160 //    c = min(cRan, 256);
00161 //    (*s_fnVecIRanu)(airan, c);
00162 //    for (j = 0; j < c; ++j)
00163 //      *adRan = RANDBL_32new(airan[j]);
00164 //  }
00165 //}
00166 void    RanSetSeed(int *piSeed, int cSeed)
00167 {
00168     s_cNormalInStore = 0;
00169   (*s_fnRanSetSeed)(piSeed, cSeed);
00170 }
00171 void    RanSetRan(const char *sRan)
00172 {
00173     s_cNormalInStore = 0;
00174   if (strcmp(sRan, "MWC8222") == 0)
00175   {
00176     s_fnDRanu = DRan_MWC8222;
00177     s_fnIRanu = IRan_MWC8222;
00178     s_fnVecIRanu = VecIRan_MWC8222;
00179     s_fnRanSetSeed = RanSetSeed_MWC8222;
00180   }
00181   else
00182   {
00183     s_fnDRanu = NULL;
00184     s_fnIRanu = NULL;
00185     s_fnVecIRanu = NULL;
00186     s_fnRanSetSeed = NULL;
00187   }
00188 }
00189 static unsigned int IRanUfromDRanU(void)
00190 {
00191     return (unsigned int)(UINT_MAX * (*s_fnDRanu)());
00192 }
00193 static double DRanUfromIRanU(void)
00194 {
00195     return RANDBL_32new( (*s_fnIRanu)() );
00196 }
00197 void    RanSetRanExt(DRANFUN DRanFun, IRANFUN IRanFun, IVECRANFUN IVecRanFun,
00198   DVECRANFUN DVecRanFun, RANSETSEEDFUN RanSetSeedFun)
00199 {
00200   s_fnDRanu = DRanFun ? DRanFun : DRanUfromIRanU;
00201   s_fnIRanu = IRanFun ? IRanFun : IRanUfromDRanU;
00202   s_fnVecIRanu = IVecRanFun;
00203   s_fnVecDRanu = DVecRanFun;
00204   s_fnRanSetSeed = RanSetSeedFun;
00205 }
00206 /*---------------- END uniform random number generators --------------------*/
00207 
00208 
00209 /*----------------------------- Polar normal RNG ---------------------------*/
00210 #define POLARBLOCK(u1, u2, d)               \
00211   do                                        \
00212   {   u1 = (decltype(u1))(*s_fnDRanu)();  u1 = 2 * u1 - 1;\
00213     u2 = (decltype(u2))(*s_fnDRanu)();  u2 = 2 * u2 - 1;\
00214     d = u1 * u1 + u2 * u2;                \
00215   } while (d >= 1);                         \
00216   d = std::sqrt( (-2.f / d) * std::log(d) );          \
00217   u1 *= d;  u2 *= d
00218 
00219 static double s_dNormalInStore;
00220 
00221 double  DRanNormalPolar(void)                         /* Polar Marsaglia */
00222 {
00223     double d, u1;
00224 
00225     if (s_cNormalInStore)
00226         u1 = s_dNormalInStore, s_cNormalInStore = 0;
00227     else
00228     {
00229         POLARBLOCK(u1, s_dNormalInStore, d);
00230         s_cNormalInStore = 1;
00231     }
00232 
00233 return u1;
00234 }
00235 
00236 #define FPOLARBLOCK(u1, u2, d)                \
00237   do                                        \
00238   {   u1 = (float)((*s_fnDRanu)());  u1 = 2 * u1 - 1;\
00239     u2 = (float)((*s_fnDRanu)());  u2 = 2 * u2 - 1;\
00240     d = u1 * u1 + u2 * u2;                \
00241   } while (d >= 1);                         \
00242   d = std::sqrt( (-2.f / d) * std::log(d) );          \
00243   u1 *= d;  u2 *= d
00244 
00245 static float s_fNormalInStore;
00246 double  FRanNormalPolar(void)                         /* Polar Marsaglia */
00247 {
00248     float d, u1;
00249 
00250     if (s_cNormalInStore)
00251         u1 = s_fNormalInStore, s_cNormalInStore = 0;
00252     else
00253     {
00254         POLARBLOCK(u1, s_fNormalInStore, d);
00255         s_cNormalInStore = 1;
00256     }
00257 
00258 return (double)u1;
00259 }
00260 /*--------------------------- END Polar normal RNG -------------------------*/
00261 
00262 /*------------------------------ DRanQuanNormal -----------------------------*/
00263 static double dProbN(double x, int fUpper)
00264 {
00265     double p;  double y;
00266 
00267     if (x < 0)
00268         x = -x, fUpper = !fUpper;
00269     else if (x == 0)
00270         return 0.5;
00271 
00272     if ( !(x <= 8 || (fUpper && x <= 37) ) )
00273         return (fUpper) ? 0 : 1;
00274 
00275     y = x * x / 2;
00276 
00277     if (x <= 1.28)
00278     {
00279         p = 0.5 - x * (0.398942280444 - 0.399903438504 * y /
00280             (y + 5.75885480458 - 29.8213557808 /
00281             (y + 2.62433121679 + 48.6959930692 /
00282             (y + 5.92885724438))));
00283     }
00284     else
00285     {
00286         p = 0.398942280385 * exp(-y) /
00287             (x - 3.8052e-8 + 1.00000615302 /
00288             (x + 3.98064794e-4 + 1.98615381364 /
00289             (x - 0.151679116635 + 5.29330324926 /
00290             (x + 4.8385912808 - 15.1508972451 /
00291             (x + 0.742380924027 + 30.789933034 /
00292             (x + 3.99019417011))))));
00293     }
00294     return (fUpper) ? p : 1 - p;
00295 }
00296 double  DProbNormal(double x)
00297 {
00298     return dProbN(x, 0);
00299 }
00300 double  DRanQuanNormal(void)
00301 {
00302   return DProbNormal(DRanNormalPolar());
00303 }
00304 double  FRanQuanNormal(void)
00305 {
00306   return DProbNormal(FRanNormalPolar());
00307 }
00308 /*----------------------------- END DRanQuanNormal -------------------------*/
00309 
00310 #ifdef __cplusplus
00311 } //extern "C"
00312 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:53 2016 by Doxygen 1.6.3