Coverage Report

Created: 2026-09-14 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-source/src/nmath/choose.c
Line
Count
Source
1
/*
2
 *  Mathlib : A C Library of Special Functions
3
 *  Copyright (C) 2004-2025 The R Foundation
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 choose(double n, double k);
24
 *    double lchoose(double n, double k);
25
 * (and private)
26
 *    double lfastchoose(double n, double k);
27
 *
28
 *  DESCRIPTION
29
 *
30
 *  Binomial coefficients.
31
 *  choose(n, k)   and  lchoose(n,k) := log(abs(choose(n,k))
32
 *
33
 *  These work for the *generalized* binomial theorem,
34
 *  i.e., are also defined for non-integer n  (integer k).
35
 *
36
 *  We use the simple explicit product formula for  k <= k_small_max
37
 *  and also have added statements to make sure that the symmetry
38
 *    (n \\ k ) == (n \\ n-k)  is preserved for non-negative integer n.
39
 */
40
41
#include "nmath.h"
42
43
/* These are recursive, so we should do a stack check */
44
45
#ifndef MATHLIB_STANDALONE
46
void R_CheckStack(void);
47
#endif
48
49
attribute_hidden double lfastchoose(double n, double k)
50
0
{
51
0
    return -log(n + 1.) - lbeta(n - k + 1., k + 1.);
52
0
}
53
/* mathematically the same:
54
   less stable typically, but useful if n-k+1 < 0 : */
55
static
56
double lfastchoose2(double n, double k, int *s_choose)
57
0
{
58
0
    double r;
59
0
    r = lgammafn_sign(n - k + 1., s_choose);
60
0
    return lgammafn(n + 1.) - lgammafn(k + 1.) - r;
61
0
}
62
63
0
#define ODD(_K_) ((_K_) != 2 * floor((_K_) / 2.))
64
65
0
#define R_IS_INT(x)  (!R_nonint(x))
66
67
double lchoose(double n, double k)
68
0
{
69
0
    double k0 = k;
70
0
    k = R_forceint(k);
71
0
#ifdef IEEE_754
72
    /* NaNs propagated correctly */
73
0
    if(ISNAN(n) || ISNAN(k)) return n + k;
74
0
#endif
75
0
#ifndef MATHLIB_STANDALONE
76
0
    R_CheckStack();
77
0
#endif
78
0
#define non_INT_WARN_ROUNDING         \
79
    /* warn "compatibly" with nmath.h's  R_nonint() : */  \
80
0
    if (fabs(k - k0) > 1e-9 * fmax2(1., fabs(k0)))   \
81
0
  MATHLIB_WARNING2(_("'k' (%.2f) must be integer, rounded to %.0f"), k0, k);
82
83
0
    non_INT_WARN_ROUNDING;
84
0
    if (k < 2) {
85
0
  if (k <  0) return ML_NEGINF;
86
0
  if (k == 0) return 0.;
87
  /* else: k == 1 */
88
0
  return log(fabs(n));
89
0
    }
90
    /* else: k >= 2 */
91
0
    if (n < 0) {
92
0
  return lchoose(-n+ k-1, k);
93
0
    }
94
0
    else if (R_IS_INT(n)) {
95
0
  n = R_forceint(n);
96
0
  if(n < k) return ML_NEGINF;
97
  /* k <= n :*/
98
0
  if(n - k < 2) return lchoose(n, n-k); /* <- Symmetry */
99
  /* else: n >= k+2 */
100
0
  return lfastchoose(n, k);
101
0
    }
102
    /* else non-integer n >= 0 : */
103
0
    if (n < k-1) {
104
0
  int s;
105
0
  return lfastchoose2(n, k, &s);
106
0
    }
107
0
    return lfastchoose(n, k);
108
0
}
109
110
0
#define k_small_max 30
111
/* 30 is somewhat arbitrary: it is on the *safe* side:
112
 * both speed and precision are clearly improved for k < 30.
113
*/
114
double choose(double n, double k)
115
0
{
116
0
    double r, k0 = k;
117
0
    k = R_forceint(k);
118
0
#ifdef IEEE_754
119
    /* NaNs propagated correctly */
120
0
    if(ISNAN(n) || ISNAN(k)) return n + k;
121
0
#endif
122
0
#ifndef MATHLIB_STANDALONE
123
0
    R_CheckStack();
124
0
#endif
125
0
    non_INT_WARN_ROUNDING;
126
0
    if (k < k_small_max) {
127
0
  int j;
128
0
  if(n-k < k && n >= 0 && R_IS_INT(n))
129
0
      k = R_forceint(n-k); /* <- Symmetry, ensure k still integer */
130
0
  if (k <  0) return 0.;
131
0
  if (k == 0) return 1.;
132
  /* else: k >= 1 */
133
0
  r = n;
134
0
  for(j = 2; j <= k; j++)
135
0
      r *= (n-j+1)/j;
136
0
  return R_IS_INT(n) ? R_forceint(r) : r;
137
  /* might have got rounding errors */
138
0
    }
139
    /* else: k >= k_small_max */
140
0
    if (n < 0) {
141
0
  r = choose(-n+ k-1, k);
142
0
  if (ODD(k)) r = -r;
143
0
  return r;
144
0
    }
145
0
    else if (R_IS_INT(n)) {
146
0
  n = R_forceint(n);
147
0
  if(n < k) return 0.;
148
0
  if(n - k < k_small_max) return choose(n, n-k); /* <- Symmetry */
149
0
  return R_forceint(exp(lfastchoose(n, k)));
150
0
    }
151
    /* else non-integer n >= 0 : */
152
0
    if (n < k-1) {
153
0
  int s_choose;
154
0
  r = lfastchoose2(n, k, /* -> */ &s_choose);
155
0
  return s_choose * exp(r);
156
0
    }
157
0
    return exp(lfastchoose(n, k));
158
0
}