planck_rng.h

Go to the documentation of this file.
00001 /*
00002  *  This file is part of libcxxsupport.
00003  *
00004  *  libcxxsupport is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  libcxxsupport is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with libcxxsupport; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  */
00018 
00019 /*
00020  *  libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
00021  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
00022  *  (DLR).
00023  */
00024 
00025 /*! \file planck_rng.h
00026  *  This file contains the random number generator
00027  *  used by the Planck LevelS package.
00028  *  The generator is a C++ port of the xorshift generator xor128() described
00029  *  in Marsaglia, Journal of Statistical Software 2003, vol 8.
00030  *  It has a period of 2^128 - 1.
00031  *
00032  *  Copyright (C) 2003, 2004, 2005 Max-Planck-Society
00033  *  \author Martin Reinecke
00034  */
00035 
00036 #ifndef PLANCK_RNG_H
00037 #define PLANCK_RNG_H
00038 
00039 #include <cmath>
00040 #include "error_handling.h"
00041 
00042 /*! C++ port of the xorshift generator xor128() described in Marsaglia,
00043     Journal of Statistical Software 2003, vol 8.
00044     It has a period of 2^128 - 1. */
00045 class planck_rng
00046   {
00047   private:
00048     unsigned int x,y,z,w;
00049     double small, gset;
00050     bool empty;
00051 
00052     void twiddle (unsigned int &v)
00053       {
00054       for (int i=0; i<9; ++i)
00055         {
00056         v ^= v<<13;
00057         v ^= v>>17;
00058         v ^= v<<5;
00059         }
00060       }
00061 
00062     void init_rng ()
00063       {
00064       // avoid zero seeds
00065       if (x==0) x = 123456789;
00066       if (y==0) y = 362436069;
00067       if (z==0) z = 521288629;
00068       if (w==0) w = 88675123;
00069 
00070       // shuffle the bits of the seeds
00071       twiddle(x); twiddle(y); twiddle(z); twiddle(w);
00072 
00073       // burn in the RNG
00074       for (int i=0; i<16; ++i)
00075         int_rand_uni();
00076       }
00077 
00078   public:
00079     /*! Initializes the generator with 0 to 4 seed values. */
00080     planck_rng (unsigned int x1=123456789, unsigned int y1=362436069,
00081                 unsigned int z1=521288629, unsigned int w1=88675123)
00082       : x(x1), y(y1), z(z1), w(w1),
00083         small(1./(1.+double(0xFFFFFFFF))), gset(0.), empty(true)
00084       {
00085       planck_assert (sizeof(unsigned int)==4, "wrong integer size for RNG");
00086       init_rng();
00087       }
00088 
00089     /*! Re-initializes the generator with 0 to 4 seed values. */
00090     void seed (unsigned int x1=123456789, unsigned int y1=362436069,
00091       unsigned int z1=521288629, unsigned int w1=88675123)
00092       {
00093       x = x1; y = y1; z = z1; w = w1;
00094       empty = true;
00095       init_rng();
00096       }
00097 
00098     /*! Returns uniformly distributed random integer numbers from the
00099         interval [0;0xFFFFFFFF]. */
00100     unsigned int int_rand_uni()
00101       {
00102       unsigned int t = x^(x<<11);
00103       x = y;
00104       y = z;
00105       z = w;
00106 
00107       return w=(w^(w>>19))^(t^(t>>8));
00108       }
00109 
00110     //! Returns uniformly distributed random numbers from the interval [0;1[.
00111     double rand_uni()
00112       {
00113       return small*int_rand_uni();
00114       }
00115 
00116     //! Returns random numbers with Gaussian distribution (mean=0, sigma=1).
00117     /*! Uses rand_uni() internally. */
00118     double rand_gauss()
00119       {
00120       using namespace std;
00121       if (empty)
00122         {
00123         double v1,v2,rsq;
00124         do
00125           {
00126           v1=2*rand_uni()-1.;
00127           v2=2*rand_uni()-1.;
00128           rsq=v1*v1+v2*v2;
00129           }
00130         while ((rsq>=1) || (rsq==0));
00131         double fac=sqrt(-2*log(rsq)/rsq);
00132         gset=v1*fac;
00133         empty=false;
00134         return v2*fac;
00135         }
00136       else
00137         {
00138         empty=true;
00139         return gset;
00140         }
00141       }
00142 
00143     //! Returns exponentially distributed random numbers (mean=1, nonnegative)
00144     /*! Uses rand_uni() internally. */
00145     double rand_exp()
00146       {
00147       using namespace std;
00148       double val=rand_uni();
00149       if (val==0.) val=1.;
00150       return -log(val);
00151       }
00152   };
00153 
00154 #endif

Generated on Thu Oct 8 14:48:51 2015 for LevelS C++ support library