sp_random.cpp

Go to the documentation of this file.
00001 /** @file  sp_random.cpp  Evaluating random variables */
00002 
00003 /* 
00004    FAU Discrete Event System Simulator 
00005 
00006    Copyright (C) 2007  Christoph Doerr
00007    Exclusive copyright is granted to Thomas Moor
00008 */
00009 
00010 #include "sp_random.h"
00011 
00012 #include <cmath>
00013 
00014 
00015 
00016 
00017 namespace faudes {
00018 
00019 
00020 
00021 #define MODULUS    2147483647 /* DON'T CHANGE THIS VALUE                  */
00022 #define MULTIPLIER 48271      /* DON'T CHANGE THIS VALUE                  */
00023 #define CHECK      399268537  /* DON'T CHANGE THIS VALUE                  */
00024 #define STREAMS    256        /* # of streams, DON'T CHANGE THIS VALUE    */
00025 #define A256       22925      /* jump multiplier, DON'T CHANGE THIS VALUE */
00026 #define DEFAULT    123456789  /* initial seed, use 0 < DEFAULT < MODULUS  */
00027       
00028 static long ran_seed[STREAMS] = {DEFAULT};  /* current state of each stream   */
00029 static int  ran_stream        = 0;          /* stream index, 0 is the default */
00030 static int  ran_initialized   = 0;          /* test for stream initialization */
00031 
00032 
00033 //ran_plant_seeds(x)
00034 void ran_plant_seeds(long x)
00035 {
00036   const long Q = MODULUS / A256;
00037     //calculate inverse CDF (algorithm based on a rational approximation algorithm by Peter J. Acklam)
00038   const long R = MODULUS % A256;
00039   int  j;
00040   int  s;
00041 
00042   ran_initialized = 1;
00043   s = ran_stream;                            /* remember the current stream */
00044   ran_select_stream(0);                      /* change to stream 0          */
00045   ran_put_seed(x);                           /* set seed[0]                 */
00046   ran_stream = s;                            /* reset the current stream    */
00047   for (j = 1; j < STREAMS; j++) {
00048     x = A256 * (ran_seed[j - 1] % Q) - R * (ran_seed[j - 1] / Q);
00049     if (x > 0)
00050       ran_seed[j] = x;
00051     else
00052       ran_seed[j] = x + MODULUS;
00053   }
00054 }
00055 
00056 //ran_put_seed(x)
00057 void ran_put_seed(long seed)
00058 {
00059   ran_seed[ran_stream] = seed;
00060 }
00061 
00062 //ran_select_stream(index)
00063 void ran_select_stream(int index)
00064 {
00065   ran_stream = ((unsigned int) index) % STREAMS;
00066   if ((ran_initialized == 0) && (ran_stream != 0))   /* protect against        */
00067     ran_plant_seeds(DEFAULT);                        /* un-initialized streams */
00068 }
00069 
00070 //an_init(seed)
00071 void ran_init(long seed){
00072   ran_select_stream(0);                  /* select the default stream */
00073   ran_put_seed(seed);  
00074 }
00075 
00076 
00077 // ran() 
00078 double ran(void){
00079   const long Q = MODULUS / MULTIPLIER;
00080   const long R = MODULUS % MULTIPLIER;
00081   long t;
00082   
00083   t = MULTIPLIER * (ran_seed[ran_stream] % Q) - R * (ran_seed[ran_stream] / Q);
00084   if (t > 0) 
00085     ran_seed[ran_stream] = t;
00086   else 
00087     ran_seed[ran_stream] = t + MODULUS;
00088   return ((double) ran_seed[ran_stream] / MODULUS); 
00089 
00090 }
00091 
00092 
00093 // ran_uniform(a,b) 
00094 double ran_uniform(double a, double b){
00095   double q = ran();
00096   q=a*(1-q)+b*q;
00097   return q;
00098 }
00099 
00100 // ran_uniform(a,b) 
00101 long ran_uniform_int(long a, long b){
00102   double q = ran();
00103   long i =(long) floor(((double) a)*(1-q)+((double)b)*q);
00104   if(i>=b) i=b-1;
00105   if(i< a) i=a;
00106   return i;
00107 }
00108 
00109 // ran_exponential(mu) 
00110 double ran_exponential(double mu){
00111   double q=0;
00112   while(q==0){
00113     q=ran();
00114   }
00115   return -mu*log(q);
00116 }
00117 
00118 // ran_expontial(mu, tossLB, tossUB) 
00119 double ran_exponential(double mu, tpTime::Type tossLB, tpTime::Type tossUB){
00120   if(tossLB==tossUB){
00121     FD_DS("Ran_exponential(): empty interval");
00122     return tpTime::UnDef;
00123   }
00124   else{
00125     double lb= -expm1(-(static_cast<double> (tossLB))/ mu);
00126     double ub= -expm1(-(static_cast<double> (tossUB))/ mu);
00127     double u=ran_uniform(lb,ub);
00128     double ret=(-mu*(log(1-u)));
00129     //FD_DS("Ran_exponential: lb="<<lb<<" ub="<<ub<<" u="<<u<<" ret="<<ret);
00130     return ret;
00131   }
00132 }
00133 
00134 /* ran_gauss(mu, sigma, tossLB, tossUB) */
00135 double ran_gauss(double mu, double sigma, tpTime::Type tossLB, tpTime::Type tossUB){
00136   if(tossLB==tossUB){
00137     FD_DS("Ran_gauss(): empty interval");
00138     return tpTime::UnDef;
00139   }
00140   else{
00141     //Transform to (0,1)-Normaldistribution
00142     double ztossLB=(static_cast<double>(tossLB)-mu)/sigma;
00143     double ztossUB=(static_cast<double>(tossUB)-mu)/sigma;
00144     //Sample Boundaries
00145     double zlb=ran_gaussian_cdf_P(ztossLB);
00146     double zub=ran_gaussian_cdf_P(ztossUB);
00147     double u=ran_uniform(zlb,zub); 
00148 
00149     //FD_DS("Ran_gauss(): ztossLB="<<ztossLB<<" ztossUB="<<ztossUB << " zlb="<<zlb<<" zub="<<zub<<" -> u="<<u);
00150 
00151     //calculate inverse CDF (algorithm based on a rational approximation algorithm by Peter J. Acklam)
00152     double zret;
00153     static const double a[] =
00154       {
00155         -3.969683028665376e+01,
00156   2.209460984245205e+02,
00157         -2.759285104469687e+02,
00158   1.383577518672690e+02,
00159         -3.066479806614716e+01,
00160   2.506628277459239e+00
00161       };
00162       
00163     static const double b[] =
00164       {
00165         -5.447609879822406e+01,
00166   1.615858368580409e+02,
00167         -1.556989798598866e+02,
00168   6.680131188771972e+01,
00169         -1.328068155288572e+01
00170       };
00171       
00172     static const double c[] =
00173       {
00174         -7.784894002430293e-03,
00175         -3.223964580411365e-01,
00176         -2.400758277161838e+00,
00177         -2.549732539343734e+00,
00178   4.374664141464968e+00,
00179   2.938163982698783e+00
00180       };
00181       
00182     static const double d[] =
00183       {
00184         7.784695709041462e-03,
00185         3.224671290700398e-01,
00186         2.445134137142996e+00,
00187         3.754408661907416e+00
00188       };
00189     double q,r;
00190     if(u<0 || u>1) zret=0.0;
00191     else if (u==0){
00192       FD_DS("Ran_gauss(): u="<<u<<"ret=HUGE_VAL");
00193       return -HUGE_VAL;
00194     }
00195     else if (u==1){ 
00196       FD_DS("Ran_gauss(): u="<<u<<"ret=-HUGE_VAL");
00197       return HUGE_VAL;
00198     }
00199     else if (u<0.02425){
00200       // Rational approximation for lower region 
00201       q = sqrt(-2*log(u));
00202       zret=(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
00203   ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1);
00204     }  
00205     else if(u>0.97575){
00206       // Rational approximation for upper region 
00207       q  = sqrt(-2*log(1-u));
00208       zret= -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /
00209   ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1);
00210     }
00211     else{
00212       // Rational approximation for central region 
00213       q = u - 0.5;
00214       r = q*q;
00215       zret=(((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q /
00216   (((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1);
00217     }   
00218     //Transform to (mu,sigma)-Distribution
00219     double ret=(zret*sigma)+mu;    //to_do: overflow protection
00220     //FD_DS("Ran_gauss(): zret="<<zret<<" ret="<<ret); 
00221     return ret;
00222   }
00223 } 
00224 
00225 
00226 //ran_gaussian_cdf_P
00227 double ran_gaussian_cdf_P(double x){
00228   const double PI = 3.141592654;
00229   const double b1 =  0.319381530;
00230   const double b2 = -0.356563782;
00231   const double b3 =  1.781477937;
00232   const double b4 = -1.821255978;
00233   const double b5 =  1.330274429;
00234   const double p  =  0.2316419;
00235   
00236   if(x >= 0.0) {
00237     double t = 1.0 / (1.0 + p*x);
00238     return (1.0 - (1/sqrt(2*PI))*exp(-x*x/2.0 )*t* 
00239       (t*(t*(t*(t*b5 + b4) + b3) + b2) + b1));
00240   } 
00241   else { 
00242     double t = 1.0 / ( 1.0 - p * x );
00243     return ( (1/sqrt(2*PI))*exp(-x*x/2.0 )*t* 
00244        (t*(t*(t*(t*b5 + b4) + b3) + b2) + b1));
00245   }
00246 
00247 
00248 }
00249 
00250 
00251 } // name space

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen