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

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