Coverage Report

Created: 2026-09-14 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-source/src/main/random.c
Line
Count
Source
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1997--2025  The R Core Team
4
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
5
 *  Copyright (C) 2003--2018  The R Foundation
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, a copy is available at
19
 *  https://www.R-project.org/Licenses/
20
 */
21
22
#ifdef HAVE_CONFIG_H
23
# include <config.h>
24
#endif
25
26
#include <Defn.h>
27
28
#include <R_ext/Itermacros.h>
29
#include <R_ext/Random.h>
30
#include <R_ext/RS.h>   /* for R_Calloc() */
31
#include <Rmath.h>    /* for rxxx functions */
32
#include <errno.h>
33
34
/* Code down to do_random3 (inclusive) can be removed once the byte
35
  compiler knows how to optimize to .External rather than .Internal */
36
#include <Internal.h>
37
NORET static void invalid(SEXP call)
38
0
{
39
0
    error(_("invalid arguments"));
40
0
}
41
42
static bool
43
random1(double (*f) (double), double *a, R_xlen_t na, double *x, R_xlen_t n)
44
0
{
45
0
    bool naflag = false;
46
0
    double ai;
47
0
    R_xlen_t i, ia;
48
0
    errno = 0;
49
0
    MOD_ITERATE1(n, na, i, ia, {
50
0
  ai = a[ia];
51
0
  x[i] = f(ai);
52
0
  if (ISNAN(x[i])) naflag = true;
53
0
    });
54
0
    return(naflag);
55
0
}
56
57
#define RAND1(num,name) \
58
0
  case num: \
59
0
    naflag = random1(name, REAL(a), na, REAL(x), n); \
60
0
    break
61
62
63
/* "do_random1" - random sampling from 1 parameter families. */
64
/* See switch below for distributions. */
65
66
attribute_hidden SEXP do_random1(SEXP call, SEXP op, SEXP args, SEXP rho)
67
0
{
68
0
    SEXP x, a;
69
0
    R_xlen_t i, n, na;
70
0
    checkArity(op, args);
71
0
    if (!isVector(CAR(args)) || !isNumeric(CADR(args)))
72
0
  invalid(call);
73
0
    if (XLENGTH(CAR(args)) == 1) {
74
0
#ifdef LONG_VECTOR_SUPPORT
75
0
  double dn = asReal(CAR(args));
76
0
  if (ISNAN(dn) || dn < 0 || dn > R_XLEN_T_MAX)
77
0
      invalid(call);
78
0
  n = (R_xlen_t) dn;
79
#else
80
  n = asInteger(CAR(args));
81
  if (n == NA_INTEGER || n < 0)
82
      invalid(call);
83
#endif
84
0
    }
85
0
    else n = XLENGTH(CAR(args));
86
0
    PROTECT(x = allocVector(REALSXP, n));
87
0
    if (n == 0) {
88
0
  UNPROTECT(1);
89
0
  return(x);
90
0
    }
91
0
    na = XLENGTH(CADR(args));
92
0
    if (na < 1) {
93
0
  for (i = 0; i < n; i++)
94
0
      REAL(x)[i] = NA_REAL;
95
0
  warning(_("NAs produced"));
96
0
    }
97
0
    else {
98
0
  bool naflag = false;
99
0
  PROTECT(a = coerceVector(CADR(args), REALSXP));
100
0
  GetRNGstate();
101
0
  switch (PRIMVAL(op)) {
102
0
      RAND1(0, rchisq);
103
0
      RAND1(1, rexp);
104
0
      RAND1(2, rgeom);
105
0
      RAND1(3, rpois);
106
0
      RAND1(4, rt);
107
0
      RAND1(5, rsignrank);
108
0
  default:
109
0
      error("internal error in do_random1");
110
0
  }
111
0
  if (naflag)
112
0
      warning(_("NAs produced"));
113
114
0
  PutRNGstate();
115
0
  UNPROTECT(1);
116
0
    }
117
0
    UNPROTECT(1);
118
0
    return x;
119
0
}
120
121
static bool random2(double (*f) (double, double),
122
      double *a, R_xlen_t na, double *b, R_xlen_t nb,
123
      double *x, R_xlen_t n)
124
0
{
125
0
    double ai, bi;
126
0
    R_xlen_t i, ia, ib;
127
0
    bool naflag = false;
128
0
    errno = 0;
129
0
    MOD_ITERATE2(n, na, nb, i, ia, ib, {
130
0
  ai = a[ia];
131
0
  bi = b[ib];
132
0
  x[i] = f(ai, bi);
133
0
  if (ISNAN(x[i])) naflag = true;
134
0
    });
135
0
    return(naflag);
136
0
}
137
138
#define RAND2(num,name) \
139
0
  case num: \
140
0
    naflag = random2(name, REAL(a), na, REAL(b), nb, REAL(x), n); \
141
0
    break
142
143
/* "do_random2" - random sampling from 2 parameter families. */
144
/* See switch below for distributions. */
145
146
attribute_hidden SEXP do_random2(SEXP call, SEXP op, SEXP args, SEXP rho)
147
0
{
148
0
    SEXP x, a, b;
149
0
    R_xlen_t i, n, na, nb;
150
0
    checkArity(op, args);
151
0
    if (!isVector(CAR(args)) ||
152
0
  !isNumeric(CADR(args)) ||
153
0
  !isNumeric(CADDR(args)))
154
0
  invalid(call);
155
0
    if (XLENGTH(CAR(args)) == 1) {
156
0
#ifdef LONG_VECTOR_SUPPORT
157
0
  double dn = asReal(CAR(args));
158
0
  if (ISNAN(dn) || dn < 0 || dn > R_XLEN_T_MAX)
159
0
      invalid(call);
160
0
  n = (R_xlen_t) dn;
161
#else
162
  n = asInteger(CAR(args));
163
  if (n == NA_INTEGER || n < 0)
164
      invalid(call);
165
#endif
166
0
    }
167
0
    else n = XLENGTH(CAR(args));
168
0
    PROTECT(x = allocVector(REALSXP, n));
169
0
    if (n == 0) {
170
0
  UNPROTECT(1);
171
0
  return(x);
172
0
    }
173
0
    na = XLENGTH(CADR(args));
174
0
    nb = XLENGTH(CADDR(args));
175
0
    if (na < 1 || nb < 1) {
176
0
  for (i = 0; i < n; i++)
177
0
      REAL(x)[i] = NA_REAL;
178
0
  warning(_("NAs produced"));
179
0
    }
180
0
    else {
181
0
  bool naflag = false;
182
0
  PROTECT(a = coerceVector(CADR(args), REALSXP));
183
0
  PROTECT(b = coerceVector(CADDR(args), REALSXP));
184
0
  GetRNGstate();
185
0
  switch (PRIMVAL(op)) {
186
0
      RAND2(0, rbeta);
187
0
      RAND2(1, rbinom);
188
0
      RAND2(2, rcauchy);
189
0
      RAND2(3, rf);
190
0
      RAND2(4, rgamma);
191
0
      RAND2(5, rlnorm);
192
0
      RAND2(6, rlogis);
193
0
      RAND2(7, rnbinom);
194
0
      RAND2(8, rnorm);
195
0
      RAND2(9, runif);
196
0
      RAND2(10, rweibull);
197
0
      RAND2(11, rwilcox);
198
0
      RAND2(12, rnchisq);
199
0
      RAND2(13, rnbinom_mu);
200
0
  default:
201
0
      error("internal error in do_random2");
202
0
  }
203
0
  if (naflag)
204
0
      warning(_("NAs produced"));
205
206
0
  PutRNGstate();
207
0
  UNPROTECT(2);
208
0
    }
209
0
    UNPROTECT(1);
210
0
    return x;
211
0
}
212
213
static bool
214
random3(double (*f) (double, double, double), double *a,
215
  R_xlen_t na, double *b, R_xlen_t nb, double *c, R_xlen_t nc,
216
  double *x, R_xlen_t n)
217
0
{
218
0
    double ai, bi, ci;
219
0
    R_xlen_t i, ia, ib, ic;
220
0
    bool naflag = false;
221
0
    errno = 0;
222
0
    MOD_ITERATE3(n, na, nb, nc, i, ia, ib, ic, {
223
0
  ai = a[ia];
224
0
  bi = b[ib];
225
0
  ci = c[ic];
226
0
  x[i] = f(ai, bi, ci);
227
0
  if (ISNAN(x[i])) naflag = true;
228
0
    });
229
0
    return(naflag);
230
0
}
231
232
#define RAND3(num,name) \
233
0
  case num: \
234
0
    naflag = random3(name, REAL(a), na, REAL(b), nb, REAL(c), nc, REAL(x), n); \
235
0
    break
236
237
238
/* "do_random3" - random sampling from 3 parameter families. */
239
/* See switch below for distributions. */
240
241
attribute_hidden SEXP do_random3(SEXP call, SEXP op, SEXP args, SEXP rho)
242
0
{
243
0
    SEXP x, a, b, c;
244
0
    R_xlen_t i, n, na, nb, nc;
245
0
    checkArity(op, args);
246
0
    if (!isVector(CAR(args))) invalid(call);
247
0
    if (LENGTH(CAR(args)) == 1) {
248
0
#ifdef LONG_VECTOR_SUPPORT
249
0
  double dn = asReal(CAR(args));
250
0
  if (ISNAN(dn) || dn < 0 || dn > R_XLEN_T_MAX)
251
0
      invalid(call);
252
0
  n = (R_xlen_t) dn;
253
#else
254
  n = asInteger(CAR(args));
255
  if (n == NA_INTEGER || n < 0)
256
      invalid(call);
257
#endif
258
0
    }
259
0
    else n = XLENGTH(CAR(args));
260
0
    PROTECT(x = allocVector(REALSXP, n));
261
0
    if (n == 0) {
262
0
  UNPROTECT(1);
263
0
  return(x);
264
0
    }
265
266
0
    args = CDR(args); a = CAR(args);
267
0
    args = CDR(args); b = CAR(args);
268
0
    args = CDR(args); c = CAR(args);
269
0
    if (!isNumeric(a) || !isNumeric(b) || !isNumeric(c))
270
0
  invalid(call);
271
0
    na = XLENGTH(a);
272
0
    nb = XLENGTH(b);
273
0
    nc = XLENGTH(c);
274
0
    if (na < 1 || nb < 1 || nc < 1) {
275
0
  for (i = 0; i < n; i++)
276
0
      REAL(x)[i] = NA_REAL;
277
0
  warning(_("NAs produced"));
278
0
    }
279
0
    else {
280
0
  bool naflag = false;
281
0
  PROTECT(a = coerceVector(a, REALSXP));
282
0
  PROTECT(b = coerceVector(b, REALSXP));
283
0
  PROTECT(c = coerceVector(c, REALSXP));
284
0
  GetRNGstate();
285
0
  switch (PRIMVAL(op)) {
286
0
      RAND3(0, rhyper);
287
0
  default:
288
0
      error("internal error in do_random3");
289
0
  }
290
0
  if (naflag)
291
0
      warning(_("NAs produced"));
292
293
0
  PutRNGstate();
294
0
  UNPROTECT(3);
295
0
    }
296
0
    UNPROTECT(1);
297
0
    return x;
298
0
}
299
300
301
/*
302
 *  Unequal Probability Sampling.
303
 *
304
 *  Modelled after Fortran code provided by:
305
 *    E. S. Venkatraman <venkat@biosta.mskcc.org>
306
 *  but with significant modifications in the
307
 *  "with replacement" case.
308
 */
309
310
/* Unequal probability sampling; with-replacement case */
311
312
static void ProbSampleReplace(int n, double *p, int *perm, int nans, int *ans)
313
0
{
314
0
    double rU;
315
0
    int i, j;
316
0
    int nm1 = n - 1;
317
318
    /* record element identities */
319
0
    for (i = 0; i < n; i++)
320
0
  perm[i] = i + 1;
321
322
    /* sort the probabilities into descending order */
323
0
    revsort(p, perm, n);
324
325
    /* compute cumulative probabilities */
326
0
    for (i = 1 ; i < n; i++)
327
0
  p[i] += p[i - 1];
328
329
    /* compute the sample */
330
0
    for (i = 0; i < nans; i++) {
331
0
  rU = unif_rand();
332
0
  for (j = 0; j < nm1; j++) {
333
0
      if (rU <= p[j])
334
0
    break;
335
0
  }
336
0
  ans[i] = perm[j];
337
0
    }
338
0
}
339
340
/* A  version using Walker's alias method, based on Alg 3.13B in
341
   Ripley (1987).
342
 */
343
344
0
#define SMALL 10000
345
static void
346
walker_ProbSampleReplace(int n, double *p, int *a, int nans, int *ans)
347
0
{
348
0
    int *HL;
349
0
    double *q;
350
351
    /* Create the alias tables.
352
       The idea is that for HL[0] ... L-1 label the entries with q < 1
353
       and L ... H[n-1] label those >= 1.
354
       By rounding error we could have q[i] < 1. or > 1. for all entries.
355
     */
356
0
    if(n <= SMALL) {
357
0
  R_CheckStack2(n *(sizeof(int) + sizeof(double)));
358
  /* might do this repeatedly, so speed matters */
359
0
  HL = (int *) alloca(n * sizeof(int));
360
0
  q = (double *) alloca(n * sizeof(double));
361
0
    } else {
362
  /* Slow enough anyway not to risk overflow */
363
0
  HL = R_Calloc(n, int);
364
0
  q = R_Calloc(n, double);
365
0
    }
366
0
    int *H = HL, *L = HL + n;
367
0
    for (int i = 0; i < n; i++) {
368
0
  q[i] = p[i] * n;
369
0
  if (q[i] < 1.) *H++ = i; else *--L = i;
370
0
    }
371
0
    if (H > HL && L < HL + n) { /* So some q[i] are >= 1 and some < 1 */
372
0
  for (int k = 0; k < n - 1; k++) {
373
0
      int i = HL[k];
374
0
      int j = *L;
375
0
      a[i] = j;
376
0
      q[j] += q[i] - 1.;
377
0
      if (q[j] < 1.) L++;
378
0
      if(L >= HL + n) break; /* now all are >= 1 */
379
0
  }
380
0
    }
381
0
    for (int i = 0; i < n; i++) q[i] += i;
382
383
    /* generate sample */
384
0
    Sampletype Sample_kind = R_sample_kind();
385
0
    double rU;
386
0
    for (int i = 0; i < nans; i++) {
387
0
  int k;
388
0
  if (Sample_kind == ROUNDING) {
389
0
      rU = unif_rand() * n;
390
0
      k = (int) rU;
391
0
  }
392
0
  else {
393
0
      k = (int) R_unif_index(n);
394
0
      rU = k + unif_rand();
395
0
  }
396
0
  ans[i] = (rU < q[k]) ? k+1 : a[k]+1;
397
0
    }
398
0
    if(n > SMALL) {
399
0
  R_Free(HL);
400
0
  R_Free(q);
401
0
    }
402
0
}
403
404
405
/* Unequal probability sampling; without-replacement case */
406
407
static void ProbSampleNoReplace(int n, double *p, int *perm,
408
        int nans, int *ans)
409
0
{
410
0
    double rT, mass, totalmass;
411
0
    int i, j, k, n1;
412
413
    /* Record element identities */
414
0
    for (i = 0; i < n; i++)
415
0
  perm[i] = i + 1;
416
417
    /* Sort probabilities into descending order */
418
    /* Order element identities in parallel */
419
0
    revsort(p, perm, n);
420
421
    /* Compute the sample */
422
0
    totalmass = 1;
423
0
    for (i = 0, n1 = n-1; i < nans; i++, n1--) {
424
0
  rT = totalmass * unif_rand();
425
0
  mass = 0;
426
0
  for (j = 0; j < n1; j++) {
427
0
      mass += p[j];
428
0
      if (rT <= mass)
429
0
    break;
430
0
  }
431
0
  ans[i] = perm[j];
432
0
  totalmass -= p[j];
433
0
  for(k = j; k < n1; k++) {
434
0
      p[k] = p[k + 1];
435
0
      perm[k] = perm[k + 1];
436
0
  }
437
0
    }
438
0
}
439
440
static void FixupProb(double *p, int n, int require_k, bool replace)
441
0
{
442
0
    double sum = 0.0;
443
0
    int npos = 0;
444
0
    for (int i = 0; i < n; i++) {
445
0
  if (!R_FINITE(p[i]))
446
0
      error(_("NA in probability vector"));
447
0
  if (p[i] < 0.0)
448
0
      error(_("negative probability"));
449
0
  if (p[i] > 0.0) {
450
0
      npos++;
451
0
      sum += p[i];
452
0
  }
453
0
    }
454
0
    if (npos == 0 || (!replace && require_k > npos))
455
0
  error(_("too few positive probabilities"));
456
0
    for (int i = 0; i < n; i++) p[i] /= sum;
457
0
}
458
459
/* do_sample - probability sampling with/without replacement.
460
   .Internal(sample(n, size, replace, prob))
461
*/
462
attribute_hidden SEXP do_sample(SEXP call, SEXP op, SEXP args, SEXP rho)
463
0
{
464
0
    SEXP x, y, sn, sk, prob, sreplace;
465
466
0
    checkArity(op, args);
467
0
    sn = CAR(args); args = CDR(args);
468
0
    sk = CAR(args); args = CDR(args); /* size */
469
0
    if (length(sk) != 1)
470
0
  error(_("invalid '%s' argument"), "size");
471
0
    sreplace = CAR(args); args = CDR(args);
472
0
    if(length(sreplace) != 1)
473
0
   error(_("invalid '%s' argument"), "replace");
474
0
    int replace = asLogical(sreplace);
475
0
    prob = CAR(args);
476
0
    if (replace == NA_LOGICAL)
477
0
  error(_("invalid '%s' argument"), "replace");
478
0
    GetRNGstate();
479
0
    if (!isNull(prob)) {
480
0
  int n = asInteger(sn), k = asInteger(sk);
481
0
  if (n == NA_INTEGER || n < 0 || (k > 0 && n == 0))
482
0
      error(_("invalid first argument"));
483
0
  if (k == NA_INTEGER || k < 0)
484
0
      error(_("invalid '%s' argument"), "size");
485
0
  if (!replace && k > n)
486
0
      error(_("cannot take a sample larger than the population when 'replace = FALSE'"));
487
0
  PROTECT(y = allocVector(INTSXP, k));
488
0
  prob = coerceVector(prob, REALSXP);
489
0
  if (MAYBE_REFERENCED(prob)) prob = duplicate(prob);
490
0
  PROTECT(prob);
491
0
  double *p = REAL(prob);
492
0
  if (length(prob) != n)
493
0
      error(_("incorrect number of probabilities"));
494
0
  FixupProb(p, n, k, (bool) replace);
495
0
  PROTECT(x = allocVector(INTSXP, n));
496
0
  if (replace) {
497
0
      int i, nc = 0;
498
0
      for (i = 0; i < n; i++) if(n * p[i] > 0.1) nc++;
499
0
      if (nc > 200)
500
0
    walker_ProbSampleReplace(n, p, INTEGER(x), k, INTEGER(y));
501
0
      else
502
0
    ProbSampleReplace(n, p, INTEGER(x), k, INTEGER(y));
503
0
  } else
504
0
      ProbSampleNoReplace(n, p, INTEGER(x), k, INTEGER(y));
505
0
  UNPROTECT(2);
506
0
    }
507
0
    else {  // uniform sampling
508
0
  double dn = asReal(sn);
509
0
  R_xlen_t k = asVecSize(sk);
510
0
  if (!R_FINITE(dn) || dn < 0 || dn > 4.5e15 || (k > 0 && dn == 0))
511
0
      error(_("invalid first argument"));
512
0
  if (k < 0) error(_("invalid '%s' argument"), "size"); // includes NA
513
0
  if (!replace && k > dn)
514
0
      error(_("cannot take a sample larger than the population when 'replace = FALSE'"));
515
0
  if (dn > INT_MAX || k > INT_MAX) {
516
0
      PROTECT(y = allocVector(REALSXP, k));
517
0
      if (replace) {
518
0
    double *ry = REAL(y);
519
0
    for (R_xlen_t i = 0; i < k; i++) ry[i] = R_unif_index(dn) + 1;
520
0
      } else {
521
0
#ifdef LONG_VECTOR_SUPPORT
522
0
    R_xlen_t n = (R_xlen_t) dn;
523
0
    double *x = (double *)R_alloc(n, sizeof(double));
524
0
    double *ry = REAL(y);
525
0
    for (R_xlen_t i = 0; i < n; i++) x[i] = (double) i;
526
0
    for (R_xlen_t i = 0; i < k; i++) {
527
0
        R_xlen_t j = (R_xlen_t) R_unif_index(n);
528
0
        ry[i] = x[j] + 1;
529
0
        x[j] = x[--n];
530
0
    }
531
#else
532
    error(_("n >= 2^31, replace = FALSE is only supported on 64-bit platforms"));
533
#endif
534
0
      }
535
0
  } else {
536
0
      int n = (int) dn;
537
0
      PROTECT(y = allocVector(INTSXP, k));
538
0
      int *iy = INTEGER(y);
539
      /* avoid allocation for a single sample */
540
0
      if (replace || k < 2) {
541
0
    for (int i = 0; i < k; i++) iy[i] = (int)(R_unif_index(n) + 1);
542
0
      } else {
543
0
    int *x = (int *)R_alloc(n, sizeof(int));
544
0
    for (int i = 0; i < n; i++) x[i] = i;
545
0
    for (int i = 0; i < k; i++) {
546
0
        int j = (int)(R_unif_index(n));
547
0
        iy[i] = x[j] + 1;
548
0
        x[j] = x[--n];
549
0
    }
550
0
      }
551
0
  }
552
0
    }
553
0
    PutRNGstate();
554
0
    UNPROTECT(1);
555
0
    return y;
556
0
}