File: igngeom.c

package info (click to toggle)
scilab 4.0-12
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 100,640 kB
  • ctags: 57,333
  • sloc: ansic: 377,889; fortran: 242,862; xml: 179,819; tcl: 42,062; sh: 10,593; ml: 9,441; makefile: 4,377; cpp: 1,354; java: 621; csh: 260; yacc: 247; perl: 130; lex: 126; asm: 72; lisp: 30
file content (70 lines) | stat: -rw-r--r-- 2,118 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
 *  PURPOSE
 *     generate a random deviate from G(p) : the geometric
 *     law. If a r.v. X ~ G(p), X is the number of Bernouilli trials
 *     (B(p)) until succes is met. So X take its values in
 *
 *         {1, 2, 3, ...., } 
 *
 *     and  P(X=i) = p * (1-p)^(i-1) 
 *
 *  METHOD 
 *     inversion of the cdf leads to :
 *
 *     (1)   X = 1 + floor( log(1-u) / log(1-p) )
 *
 *     u being a random deviate from U[0,1).
 *
 *     by taking into account that 1-u follows also U(0,1)) this may be 
 *     replaced with X = ceil( log(u) / log(1-p) ) or 1 + floor(log(u)/log(1-p))
 *     which needs less work. But as ranf() provides number in [0,1[ , 0 may be 
 *     gotten and these formulae may give then +oo.
 * 
 *     With ranf() the max number is 1 - 2^(-32). This let us choose a safe min
 *     value for p (to avoid a +oo due to log(1-p)) in the following manner :
 *
 *        the max is gotten for  M = log(2^(-32)) / (-p)
 *
 *     (for very small |x|, the accurate func logp1(x):=log(1+x) return simply x)
 *
 *     and we want  M <= Rmax (near 1.798+308 in ieee 754 double)
 *
 *     so p >= 32 log(2)/Rmax which is near 1.234e-307 ; Says pmin = 1.3e-307.
 *     (anyway the results gotten for such small values of p are certainly 
 *      not meaningful...)
 *
 *  NOTE
 *     this function returns a double instead of an integer type : this is 
 *     to avoid an extra conversion because in scilab it will be a double.
 *
 *  ASSUMPTION
 *     p must be in [pmin,1]  (to do at the calling level).
 *
 *  AUTHOR
 *     Bruno Pincon (<Bruno.Pincon@iecn.u-nancy.fr>)
 *
 */
#include "../stack-c.h"
#include <math.h>

/* the external functions used  here : */
double F2C(logp1)(double *x);  /* celle-ci est ds SCI/routines/calelm/watan.f */
double C2F(ranf)();


double igngeom(double p)
{
  static double p_save = 1.0, ln_1_m_p = 0.0;
  double u;

  if ( p == 1 ) 
    return ( 1.0 );
  else if ( p != p_save )   /* => recompute log(1-p) */
    {
      p_save = p; u = -p; ln_1_m_p = F2C(logp1)(&u);
    };
  
  u = -C2F(ranf)();
  return ( floor( 1.0 + F2C(logp1)(&u)/ln_1_m_p) );
}