Coverage Report

Created: 2026-10-16 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-source/src/nmath/rgamma.c
Line
Count
Source
1
/*
2
 *  Mathlib : A C Library of Special Functions
3
 *  Copyright (C) 2000--2024 The R Core Team
4
 *  Copyright (C) 1998 Ross Ihaka
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, a copy is available at
18
 *  https://www.R-project.org/Licenses/
19
 *
20
 *  SYNOPSIS
21
 *
22
 *    #include <Rmath.h>
23
 *    double rgamma(double a, double scale);
24
 *
25
 *  DESCRIPTION
26
 *
27
 *    Random variates from the gamma distribution.
28
 *
29
 *  REFERENCES
30
 *
31
 *    [1] Shape parameter a >= 1.  Algorithm GD in:
32
 *
33
 *    Ahrens, J.H. and Dieter, U. (1982).
34
 *    Generating gamma variates by a modified
35
 *    rejection technique.
36
 *    Comm. ACM, 25, 47-54.
37
 *
38
 *
39
 *    [2] Shape parameter 0 < a < 1. Algorithm GS in:
40
 *
41
 *    Ahrens, J.H. and Dieter, U. (1974).
42
 *    Computer methods for sampling from gamma, beta,
43
 *    poisson and binomial distributions.
44
 *    Computing, 12, 223-246.
45
 *
46
 *  Input : a     = 'shape' = alpha,
47
 *          scale = 'scale' = 1/rate of the gamma distribution w/ mean E[.] = a * scale
48
 *  Output: a variate from the gamma(a, scale)-distribution
49
 */
50
51
#include "nmath.h"
52
53
0
#define repeat for(;;)
54
55
double rgamma(double a, double scale)
56
0
{
57
/* Constants : */
58
0
    const static double sqrt32 = 5.656854;
59
0
    const static double exp_m1 = 0.36787944117144232159;/* exp(-1) = 1/e */
60
61
    /* Coefficients q[k] - for q0 = sum(q[k]*a^(-k))
62
     * Coefficients a[k] - for q = q0+(t*t/2)*sum(a[k]*v^k)
63
     * Coefficients e[k] - for exp(q)-1 = sum(e[k]*q^k)
64
     */
65
0
    const static double q1 = 0.04166669;
66
0
    const static double q2 = 0.02083148;
67
0
    const static double q3 = 0.00801191;
68
0
    const static double q4 = 0.00144121;
69
0
    const static double q5 = -7.388e-5;
70
0
    const static double q6 = 2.4511e-4;
71
0
    const static double q7 = 2.424e-4;
72
73
0
    const static double a1 = 0.3333333;
74
0
    const static double a2 = -0.250003;
75
0
    const static double a3 = 0.2000062;
76
0
    const static double a4 = -0.1662921;
77
0
    const static double a5 = 0.1423657;
78
0
    const static double a6 = -0.1367177;
79
0
    const static double a7 = 0.1233795;
80
81
    /* State variables [FIXME for threading!] :*/
82
0
    static double aa = 0.;
83
0
    static double aaa = 0.;
84
0
    static double s, s2, d;    /* no. 1 (step 1) */
85
0
    static double q0, b, si, c;/* no. 2 (step 4) */
86
87
0
    double e, p, q, r, t, u, v, w, x, ret_val;
88
89
0
    if (ISNAN(a) || ISNAN(scale))
90
0
  ML_WARN_return_NAN;
91
0
    if (a <= 0.0 || scale <= 0.0) {
92
0
  if(scale == 0. || a == 0.) return 0.;
93
0
  ML_WARN_return_NAN;
94
0
    }
95
0
    if(!R_FINITE(a) || !R_FINITE(scale)) return ML_POSINF;
96
97
0
    if (a < 1.) { /* GS algorithm for parameters a < 1 */
98
0
  e = 1.0 + exp_m1 * a;
99
0
  repeat {
100
0
      p = e * unif_rand();
101
0
      if (p >= 1.0) {
102
0
    x = -log((e - p) / a);
103
0
    if (exp_rand() >= (1.0 - a) * log(x))
104
0
        break;
105
0
      } else { /* p < 1  <==>  log(p) < 0 */
106
0
    x = exp(log(p) / a); // exp(*) "often" underflows to 0 for small a (e.g. a = 1/1000)
107
0
    if (exp_rand() >= x)
108
0
        break;
109
0
      }
110
0
  }
111
0
  return scale * x;
112
0
    }
113
114
    /* --- a >= 1 : GD algorithm --- */
115
116
    /* Step 1: Recalculations of s2, s, d if a has changed */
117
0
    if (a != aa) {
118
0
  aa = a;
119
0
  s2 = a - 0.5;
120
0
  s = sqrt(s2);
121
0
  d = sqrt32 - s * 12.0;
122
0
    }
123
    /* Step 2: t = standard normal deviate,
124
               x = (s,1/2) -normal deviate. */
125
126
    /* immediate acceptance (i) */
127
0
    t = norm_rand();
128
0
    x = s + 0.5 * t;
129
0
    ret_val = x * x;
130
0
    if (t >= 0.0)
131
0
  return scale * ret_val;
132
133
    /* Step 3: u = 0,1 - uniform sample. squeeze acceptance (s) */
134
0
    u = unif_rand();
135
0
    if (d * u <= t * t * t)
136
0
  return scale * ret_val;
137
138
    /* Step 4: recalculations of q0, b, si, c if necessary */
139
140
0
    if (a != aaa) {
141
0
  aaa = a;
142
0
  r = 1.0 / a;
143
0
  q0 = ((((((q7 * r + q6) * r + q5) * r + q4) * r + q3) * r
144
0
         + q2) * r + q1) * r;
145
146
  /* Approximation depending on size of parameter a */
147
  /* The constants in the expressions for b, si and c */
148
  /* were established by numerical experiments */
149
150
0
  if (a <= 3.686) {
151
0
      b = 0.463 + s + 0.178 * s2;
152
0
      si = 1.235;
153
0
      c = 0.195 / s - 0.079 + 0.16 * s;
154
0
  } else if (a <= 13.022) {
155
0
      b = 1.654 + 0.0076 * s2;
156
0
      si = 1.68 / s + 0.275;
157
0
      c = 0.062 / s + 0.024;
158
0
  } else {
159
0
      b = 1.77;
160
0
      si = 0.75;
161
0
      c = 0.1515 / s;
162
0
  }
163
0
    }
164
    /* Step 5: no quotient test if x not positive */
165
166
0
    if (x > 0.0) {
167
  /* Step 6: calculation of v and quotient q */
168
0
  v = t / (s + s);
169
0
  if (fabs(v) <= 0.25)
170
0
      q = q0 + 0.5 * t * t * ((((((a7 * v + a6) * v + a5) * v + a4) * v
171
0
              + a3) * v + a2) * v + a1) * v;
172
0
  else
173
0
      q = q0 - s * t + 0.25 * t * t + (s2 + s2) * log(1.0 + v);
174
175
176
  /* Step 7: quotient acceptance (q) */
177
0
  if (log(1.0 - u) <= q)
178
0
      return scale * ret_val;
179
0
    }
180
181
0
    repeat {
182
  /* Step 8: e = standard exponential deviate
183
   *  u =  0,1 -uniform deviate
184
   *  t = (b,si)-double exponential (laplace) sample */
185
0
  e = exp_rand();
186
0
  u = unif_rand();
187
0
  u = u + u - 1.0;
188
0
  if (u < 0.0)
189
0
      t = b - si * e;
190
0
  else
191
0
      t = b + si * e;
192
  /* Step  9:  rejection if t < tau(1) = -0.71874483771719 */
193
0
  if (t >= -0.71874483771719) {
194
      /* Step 10:  calculation of v and quotient q */
195
0
      v = t / (s + s);
196
0
      if (fabs(v) <= 0.25)
197
0
    q = q0 + 0.5 * t * t *
198
0
        ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v
199
0
          + a2) * v + a1) * v;
200
0
      else
201
0
    q = q0 - s * t + 0.25 * t * t + (s2 + s2) * log(1.0 + v);
202
      /* Step 11:  hat acceptance (h) */
203
      /* (if q not positive go to step 8) */
204
0
      if (q > 0.0) {
205
0
    w = expm1(q);
206
    /*  ^^^^^ original code had approximation with rel.err < 2e-7 */
207
    /* if t is rejected sample again at step 8 */
208
0
    if (c * fabs(u) <= w * exp(e - 0.5 * t * t))
209
0
        break;
210
0
      }
211
0
  }
212
0
    } /* repeat .. until  `t' is accepted */
213
0
    x = s + 0.5 * t;
214
0
    return scale * x * x;
215
0
}