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

Tekkotsu v4.0
Generated Thu Nov 22 00:54:57 2007 by Doxygen 1.5.4