Go back to Random distributions
<project-file type=“source”/> <content> /* this file implements a gamma distribution generator. It is shamelessly
copied from the gsl (Gnu Science Library) code, and adapted to my own need. The original copyright message is provided below. */
/* randist/gamma.c * * Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, Brian Gough * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include “genrand2.h” #include <math.h>
static float gamma_large ( const float a); static float gamma_frac (const float a); static float gsl_ran_gamma_int (const unsigned int a);
/* The Gamma distribution of order a>0 is defined by:
p(x) dx = {1 / \Gamma(a) b^a } x^{a-1} e^{-x/b} dx
for x>0. If X and Y are independent gamma-distributed random variables of order a1 and a2 with the same scale parameter b, then X+Y has gamma distribution of order a1+a2.
The algorithms below are from Knuth, vol 2, 2nd ed, p. 129. */
float gammaRandom (const float a, const float b) {
/* assume a > 0 */ unsigned int na = (int)floor (a);
if (a == na) { return b * gsl_ran_gamma_int (na); } else if (na == 0) { return b * gamma_frac (a); } else { return b * (gsl_ran_gamma_int (na) + gamma_frac (a - na)) ; }
}
float gsl_ran_gamma_int (const unsigned int a) {
if (a < 12) { unsigned int i; float prod = 1,r;
for (i = 0; i < a; i++) { do { r=genrand2d(); } while (r==0); prod *= r; }
/* Note: for 12 iterations we are safe against underflow, since the smallest positive random number is O(2^-32). This means the smallest possible product is 2^(-12*32) = 10^-116 which is within the range of float precision. */
return -log (prod); } else { return gamma_large ((float) a); }
}
static float gamma_large (const float a) {
/* Works only if a > 1, and is most efficient if a is large
This algorithm, reported in Knuth, is attributed to Ahrens. A faster one, we are told, can be found in: J. H. Ahrens and U. Dieter, Computing 12 (1974) 223-246. */
float sqa, x, y, v; sqa = sqrt (2 * a - 1); do { do { y = tan (M_PI * genrand2d()); x = sqa * y + a - 1; } while (x <= 0); v = genrand2d(); } while (v > (1 + y * y) * exp ((a - 1) * log (x / (a - 1)) - sqa * y));
return x;
}
static float gamma_frac (const float a) {
/* This is exercise 16 from Knuth; see page 135, and the solution is on page 551. */
float p, q, x, u, v; p = M_E / (a + M_E); do { u = genrand2d(); do { v = genrand2d(); } while (v==0);
if (u < p) { x = exp ((1 / a) * log (v)); q = exp (-x); } else { x = 1 - log (v); q = exp ((a - 1) * log (x)); } } while (genrand2d() >= q);
return x;
} </content> <use name=“genrand2.h”/>