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
1.5.1