File: random.c

package info (click to toggle)
cufflinks 1.3.0-2
  • links: PTS, VCS
  • area: non-free
  • in suites: wheezy
  • size: 3,864 kB
  • sloc: cpp: 48,999; ansic: 12,297; sh: 3,381; python: 432; makefile: 209
file content (147 lines) | stat: -rw-r--r-- 3,267 bytes parent folder | download | duplicates (5)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 *   Copyright (c) 1996-2000 Lucent Technologies.
 *   See README file for details.
 */

#include "local.h"

#define PI_HALF         1.5707963267948966192313216916397514420986 /*pi/2*/
#define PI_QUARTER      0.7853981633974483096156608458198757210493 /*pi/4*/
#define EXP78           1.0129030479320018583185514777512982888868 /*e^(1/78)*/
#define PI128          40.7436654315252059568342434233636766808217 /*128/pi*/

static unsigned long cc, tv, ss=1;

double runif()
{	if (ss)
	{ WARN(("runif: No seed set."));
          return(0.0);
	}
        cc = cc * 69069;    /* congruential part */
        tv ^= tv >> 15;       /* tausworthe part */
        tv ^= tv << 17;
	return(((tv ^ cc) >> 1) / 2147483648.0);
}

void rseed(seed)
/*
  Seed should be string of at least 8 characters.
*/
char *seed;
{	ss = 0;
	tv = seed[0];
        tv = (tv<<8) | seed[1];
        tv = (tv<<8) | seed[2];
        tv = (tv<<8) | seed[3];
 	cc = seed[4];
        cc = (cc<<8) | seed[5];
        cc = (cc<<8) | seed[6];
        cc = (cc<<8) | seed[7];
        if(cc % 2 == 0)
             cc++;
}

/*
 * Gaussian random variable.
 * Reference: Kinderman & Monahan, Proceedings of
 * the ASA, Statistical Computing Section, 1975, 128-131.
 */
double rnorm(mu,s)
double mu, s;
{
	double rnormk, u, x2;

	do {
		u = runif();
		rnormk = 1.715527769 * (runif()-0.5) / u;
		x2 = rnormk * rnormk / 4;
	} while((x2>1-u) || (x2 > -log(u)));
	return(mu+s*rnormk);
}

double rexp(lb)
double lb;
{ return(-log(runif())/lb);
}

/*
 * Poisson random variable.
 * Simple algorithm for small lambda, else complex algorithm.
 * Crossover point must be at least 5 for the complex algorithm
 * to work correctly.
 * Reference: Devroye, pages 504, 511 and 516 (with corrections!)
 */
double rpois(lambda)
double lambda;
{
	static double olambda = -1, a, mu, delta, d, c1, c2, c3, c4, c5;
	double u, e, n, x, y, w, t, p, q;
	int new = lambda != olambda;

	olambda = lambda;
	if(lambda < 8) {
		if(new)
			a = exp(-lambda);
		q = 1;
		x = -1;
		do {
			q *= runif();
			x++;
		} while(q >= a);
		return(x);
	}

	if(new) {
		mu = floor(lambda);
		delta = sqrt(2 * mu * log(mu * PI128));
		delta = MAX(6.0, MIN(mu, floor(delta)));
		d = 2*mu + delta;
		c1 = sqrt(mu * PI_HALF);
		c2 = c1 + sqrt(d * PI_QUARTER) * exp(1/d);
		c3 = c2 + 1;
		c4 = c3 + EXP78;
		c5 = c4 + 2 * d * exp(-delta*(1+delta/2)/d) / delta;
	}
	while(1) {
		u = c5 * runif();
		e = -log(runif());
		if(u <= c1) {
			n = rnorm(0.0,1.0);
			x = floor(-fabs(n) * sqrt(mu));
			if(x < -mu)
				continue;
			w = n*n/2 + e + x*log(lambda/mu);
		} else if(u <= c2) {
			y = 1 + fabs(rnorm(0.0,1.0)) * sqrt(d/2);
			x = ceil(y);
			if(x > delta)
				continue;
			w = y*(y-2)/d + e + x*log(lambda/mu);
		} else if(u <= c3) {
			x = 0;
			w = e;
		} else if(u <= c4) {
			x = 1;
			w = e + log(lambda/mu);
		} else {
			y = delta - 2*d*log(runif())/delta;
			x = ceil(y);
			w = delta*(1+y/2)/d + e + x*log(lambda/mu);
		}
		w = -w;
		t = x*(x+1) / (2*mu);
		if(x >= 0 && w <= -t)
			return(x+mu);
		if(x < 0 && w > -t)
			continue;
		q = t * ((2*x+1)/(6*mu) - 1);
		if(w > q)
			continue;
		p = x+1 <= 0 ? x+1 : 0;
		p = q - t*t/(3*(mu+p));
		if(w <= p)
			return(x+mu);
		if(w <= x*log(mu) - LGAMMA(mu+x+1) + LGAMMA(mu+1))
			return(x+mu);
	}
}