Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

zignor.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 <math.h>
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 
00024 #include "zigrandom.h"
00025 #include "zignor.h"
00026 
00027 #ifdef __cplusplus
00028 extern "C" {
00029 #endif
00030   
00031 /*------------------------------ General Ziggurat --------------------------*/
00032 static double DRanNormalTail(double dMin, int iNegative)
00033 {
00034   double x, y;
00035   do
00036   { x = log(DRanU()) / dMin;
00037     y = log(DRanU());
00038   } while (-2 * y < x * x);
00039   return iNegative ? x - dMin : dMin - x;
00040 }
00041 
00042 #define ZIGNOR_C 128             /* number of blocks */
00043 #define ZIGNOR_R 3.442619855899 /* start of the right tail */
00044            /* (R * phi(R) + Pr(X>=R)) * sqrt(2\pi) */
00045 #define ZIGNOR_V 9.91256303526217e-3
00046 
00047 /* s_adZigX holds coordinates, such that each rectangle has*/
00048 /* same area; s_adZigR holds s_adZigX[i + 1] / s_adZigX[i] */
00049 static double s_adZigX[ZIGNOR_C + 1], s_adZigR[ZIGNOR_C];
00050 
00051 static void zigNorInit(int iC, double dR, double dV)
00052 {
00053   int i;  double f;
00054   
00055   f = exp(-0.5 * dR * dR);
00056   s_adZigX[0] = dV / f; /* [0] is bottom block: V / f(R) */
00057   s_adZigX[1] = dR;
00058   s_adZigX[iC] = 0;
00059 
00060   for (i = 2; i < iC; ++i)
00061   {
00062     s_adZigX[i] = sqrt(-2 * log(dV / s_adZigX[i - 1] + f));
00063     f = exp(-0.5 * s_adZigX[i] * s_adZigX[i]);
00064   }
00065   for (i = 0; i < iC; ++i)
00066     s_adZigR[i] = s_adZigX[i + 1] / s_adZigX[i];
00067 }
00068 double  DRanNormalZig(void)
00069 {
00070   unsigned int i;
00071   double x, u, f0, f1;
00072   
00073   for (;;)
00074   {
00075     u = 2 * DRanU() - 1;
00076     i = IRanU() & 0x7F;
00077     /* first try the rectangular boxes */
00078     if (fabs(u) < s_adZigR[i])     
00079       return u * s_adZigX[i];
00080     /* bottom box: sample from the tail */
00081     if (i == 0)           
00082       return DRanNormalTail(ZIGNOR_R, u < 0);
00083     /* is this a sample from the wedges? */
00084     x = u * s_adZigX[i];       
00085     f0 = exp(-0.5 * (s_adZigX[i] * s_adZigX[i] - x * x) );
00086     f1 = exp(-0.5 * (s_adZigX[i+1] * s_adZigX[i+1] - x * x) );
00087         if (f1 + DRanU() * (f0 - f1) < 1.0)
00088       return x;
00089   }
00090 }
00091 
00092 #define ZIGNOR_STORE 64 * 4
00093 static unsigned int s_auiZigTmp[ZIGNOR_STORE / 4];
00094 static unsigned int s_auiZigBox[ZIGNOR_STORE];
00095 static double s_adZigRan[ZIGNOR_STORE + ZIGNOR_STORE / 4];
00096 static int s_cZigStored = 0;
00097 
00098 double  DRanNormalZigVec(void)
00099 {
00100   unsigned int i, j, k;
00101   double x, u, f0, f1;
00102   
00103   for (;;)
00104   {
00105     if (s_cZigStored == 0)
00106     {
00107       RanVecIntU(s_auiZigTmp, ZIGNOR_STORE / 4);
00108       RanVecU(s_adZigRan, ZIGNOR_STORE);
00109       for (j = k = 0; j < ZIGNOR_STORE; j += 4, ++k)
00110       {
00111         i = s_auiZigTmp[k]; s_auiZigBox[j + 0] = i & 0x7F;
00112         i >>= 8;      s_auiZigBox[j + 1] = i & 0x7F;
00113         i >>= 8;      s_auiZigBox[j + 2] = i & 0x7F;
00114         i >>= 8;      s_auiZigBox[j + 3] = i & 0x7F;
00115         s_adZigRan[j + 0] = 2 * s_adZigRan[j + 0] - 1;
00116         s_adZigRan[j + 1] = 2 * s_adZigRan[j + 1] - 1;
00117         s_adZigRan[j + 2] = 2 * s_adZigRan[j + 2] - 1;
00118         s_adZigRan[j + 3] = 2 * s_adZigRan[j + 3] - 1;
00119       }
00120       s_cZigStored = j;
00121     }
00122     --s_cZigStored;
00123 
00124     u = s_adZigRan[s_cZigStored];
00125     i = s_auiZigBox[s_cZigStored];
00126     
00127     if (fabs(u) < s_adZigR[i])     /* first try the rectangular boxes */
00128       return u * s_adZigX[i];
00129 
00130     if (i == 0)           /* bottom box: sample from the tail */
00131       return DRanNormalTail(ZIGNOR_R, u < 0);
00132 
00133     x = u * s_adZigX[i];       /* is this a sample from the wedges? */
00134     f0 = exp(-0.5 * (s_adZigX[i] * s_adZigX[i] - x * x) );
00135     f1 = exp(-0.5 * (s_adZigX[i + 1] * s_adZigX[i + 1] - x * x) );
00136         if (f1 + DRanU() * (f0 - f1) < 1.0)
00137       return x;
00138   }
00139 }
00140 
00141 void  RanNormalSetSeedZig(int *piSeed, int cSeed)
00142 {
00143   zigNorInit(ZIGNOR_C, ZIGNOR_R, ZIGNOR_V);
00144   RanSetSeed(piSeed, cSeed);
00145 }
00146 void  RanNormalSetSeedZigVec(int *piSeed, int cSeed)
00147 {
00148   s_cZigStored = 0;
00149   RanNormalSetSeedZig(piSeed, cSeed);
00150 }
00151 /*--------------------------- END General Ziggurat -------------------------*/
00152 
00153 /*------------------------------ Integer Ziggurat --------------------------*/
00154 #define ZIGNOR_INVM M_RAN_INVM32
00155 
00156 static unsigned int s_aiZigRm[ZIGNOR_C];
00157 static double s_adZigXm[ZIGNOR_C + 1];
00158 
00159 static void zig32NorInit(int iC, double dR, double dV)
00160 {
00161   int i;  double f, m31 = ZIGNOR_INVM * 2;
00162 
00163   f = exp(-0.5 * dR * dR);
00164   s_adZigXm[0] = dV / f; /* [0] is bottom block: V / f(R) */
00165   s_adZigXm[1] = dR;
00166   s_adZigXm[iC] = 0;
00167 
00168   for (i = 2; i < iC; ++i)
00169   {
00170     s_adZigXm[i] = sqrt(-2 * log(dV / s_adZigXm[i - 1] + f));
00171     f = exp(-0.5 * s_adZigXm[i] * s_adZigXm[i]);
00172   }
00173   /* compute ratio and implement scaling */
00174   for (i = 0; i < iC; ++i)
00175     s_aiZigRm[i] = (unsigned int)
00176       ( (s_adZigXm[i + 1] / s_adZigXm[i]) / m31 );
00177   for (i = 0; i <= iC; ++i)
00178     s_adZigXm[i] *= m31;
00179 }
00180 double  DRanNormalZig32(void)
00181 {
00182   unsigned int i;
00183   int u;
00184   double x, y, f0, f1;
00185   
00186   for (;;)
00187   {
00188     u = (int)IRanU();
00189     i = IRanU() & 0x7F;
00190     if ((unsigned int)abs(u) < s_aiZigRm[i])/* first try the rectangles */
00191       return u * s_adZigXm[i];
00192     
00193     if (i == 0)                 /* sample from the tail */
00194       return DRanNormalTail(ZIGNOR_R, u < 0);
00195 
00196     x = u * s_adZigXm[i];      /* is this a sample from the wedges? */
00197     y = 0.5 * s_adZigXm[i] / ZIGNOR_INVM;      f0 = exp(-0.5 * (y * y - x * x) );
00198     y = 0.5 * s_adZigXm[i + 1] / ZIGNOR_INVM;  f1 = exp(-0.5 * (y * y - x * x) );
00199         if (f1 + IRanU() * ZIGNOR_INVM * (f0 - f1) < 1.0)
00200       return x;
00201   }
00202 }
00203 #define ZIGNOR32_STORE 64 * 4
00204 static unsigned int s_auiZig32Ran[ZIGNOR32_STORE];
00205 static unsigned int s_auiZig32Box[ZIGNOR32_STORE];
00206 static int s_cZig32Stored = 0;
00207 
00208 double  DRanNormalZig32Vec(void)
00209 {
00210   unsigned int i, j, k;
00211   int u;
00212   double x, y, f0, f1;
00213   
00214   for (;;)
00215   {
00216     if (s_cZig32Stored == 0)
00217     {
00218       RanVecIntU(s_auiZig32Ran, ZIGNOR32_STORE / 4);
00219       for (j = k = 0; j < ZIGNOR32_STORE; j += 4, ++k)
00220       {
00221         i = s_auiZig32Ran[k]; s_auiZig32Box[j+0] = i & 0x7F;
00222         i >>= 8;        s_auiZig32Box[j+1] = i & 0x7F;
00223         i >>= 8;        s_auiZig32Box[j+2] = i & 0x7F;
00224         i >>= 8;        s_auiZig32Box[j+3] = i & 0x7F;
00225       }
00226       RanVecIntU(s_auiZig32Ran, ZIGNOR32_STORE);
00227       s_cZig32Stored = j;
00228     }
00229     --s_cZig32Stored;
00230 
00231     u = (int)s_auiZig32Ran[s_cZig32Stored];
00232     i = s_auiZig32Box[s_cZig32Stored];
00233     /* first try the rectangles */
00234     if ((unsigned int)abs(u) < s_aiZigRm[i])
00235       return u * s_adZigXm[i];
00236     /* bottom box: sample from the tail */
00237     if (i == 0)                 
00238       return DRanNormalTail(ZIGNOR_R, u < 0);
00239     /* is this a sample from the wedges? */
00240     x = u * s_adZigXm[i];
00241     y = 0.5 * s_adZigXm[i] / ZIGNOR_INVM;
00242     f0 = exp(-0.5 * (y * y - x * x) );
00243     y = 0.5 * s_adZigXm[i + 1] / ZIGNOR_INVM;
00244     f1 = exp(-0.5 * (y * y - x * x) );
00245         if (f1 + IRanU() * ZIGNOR_INVM * (f0 - f1) < 1.0)
00246       return x;
00247   }
00248 }
00249 void  RanNormalSetSeedZig32(int *piSeed, int cSeed)
00250 {
00251   zig32NorInit(ZIGNOR_C, ZIGNOR_R, ZIGNOR_V);
00252   RanSetSeed(piSeed, cSeed);
00253 }
00254 void  RanNormalSetSeedZig32Vec(int *piSeed, int cSeed)
00255 {
00256   s_cZig32Stored = 0;
00257   RanNormalSetSeedZig32(piSeed, cSeed);
00258 }
00259 /*--------------------------- END Integer Ziggurat -------------------------*/
00260 
00261 /*--------------------------- functions for testing ------------------------*/
00262 double  DRanQuanNormalZig(void)
00263 {
00264   return DProbNormal(DRanNormalZig());
00265 }
00266 double  DRanQuanNormalZigVec(void)
00267 {
00268   return DProbNormal(DRanNormalZigVec());
00269 }
00270 double  DRanQuanNormalZig32(void)
00271 {
00272   return DProbNormal(DRanNormalZig32());
00273 }
00274 double  DRanQuanNormalZig32Vec(void)
00275 {
00276   return DProbNormal(DRanNormalZig32Vec());
00277 }
00278 /*------------------------- END functions for testing ----------------------*/
00279 
00280 #ifdef __cplusplus
00281 } //extern "C"
00282 #endif

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