igngeom.c

Go to the documentation of this file.
00001 /*
00002  *  PURPOSE
00003  *     generate a random deviate from G(p) : the geometric
00004  *     law. If a r.v. X ~ G(p), X is the number of Bernouilli trials
00005  *     (B(p)) until succes is met. So X take its values in
00006  *
00007  *         {1, 2, 3, ...., } 
00008  *
00009  *     and  P(X=i) = p * (1-p)^(i-1) 
00010  *
00011  *  METHOD 
00012  *     inversion of the cdf leads to :
00013  *
00014  *     (1)   X = 1 + floor( log(1-u) / log(1-p) )
00015  *
00016  *     u being a random deviate from U[0,1).
00017  *
00018  *     by taking into account that 1-u follows also U(0,1)) this may be 
00019  *     replaced with X = ceil( log(u) / log(1-p) ) or 1 + floor(log(u)/log(1-p))
00020  *     which needs less work. But as ranf() provides number in [0,1[ , 0 may be 
00021  *     gotten and these formulae may give then +oo.
00022  * 
00023  *     With ranf() the max number is 1 - 2^(-32). This let us choose a safe min
00024  *     value for p (to avoid a +oo due to log(1-p)) in the following manner :
00025  *
00026  *        the max is gotten for  M = log(2^(-32)) / (-p)
00027  *
00028  *     (for very small |x|, the accurate func logp1(x):=log(1+x) return simply x)
00029  *
00030  *     and we want  M <= Rmax (near 1.798+308 in ieee 754 double)
00031  *
00032  *     so p >= 32 log(2)/Rmax which is near 1.234e-307 ; Says pmin = 1.3e-307.
00033  *     (anyway the results gotten for such small values of p are certainly 
00034  *      not meaningful...)
00035  *
00036  *  NOTE
00037  *     this function returns a double instead of an integer type : this is 
00038  *     to avoid an extra conversion because in scilab it will be a double.
00039  *
00040  *  ASSUMPTION
00041  *     p must be in [pmin,1]  (to do at the calling level).
00042  *
00043  *  AUTHOR
00044  *     Bruno Pincon (<Bruno.Pincon@iecn.u-nancy.fr>)
00045  *
00046  */
00047 #include "stack-c.h"
00048 #include <math.h>
00049 
00050 /* the external functions used  here : */
00051 double F2C(logp1)(double *x);  /* celle-ci est ds SCI/routines/calelm/watan.f */
00052 double C2F(ranf)();
00053 
00054 
00055 double igngeom(double p)
00056 {
00057   static double p_save = 1.0, ln_1_m_p = 0.0;
00058   double u;
00059 
00060   if ( p == 1 ) 
00061     return ( 1.0 );
00062   else if ( p != p_save )   /* => recompute log(1-p) */
00063     {
00064       p_save = p; u = -p; ln_1_m_p = F2C(logp1)(&u);
00065     };
00066   
00067   u = -C2F(ranf)();
00068   return ( floor( 1.0 + F2C(logp1)(&u)/ln_1_m_p) );
00069 }      
00070     

Generated on Sun Mar 4 15:03:59 2007 for Scilab [trunk] by  doxygen 1.5.1