/src/r-source/src/nmath/dnbeta.c
Line | Count | Source |
1 | | /* |
2 | | * Mathlib : A C Library of Special Functions |
3 | | * Copyright (C) 2000-2021 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 dnbeta(double x, double a, double b, double ncp, int give_log); |
24 | | * |
25 | | * DESCRIPTION |
26 | | * |
27 | | * Computes the density of the noncentral beta distribution with |
28 | | * noncentrality parameter ncp. The noncentral beta distribution |
29 | | * has density: |
30 | | * |
31 | | * Inf |
32 | | * f(x|a,b,ncp) = SUM p(i) * x^(a+i-1) * (1-x)^(b-1) / B(a+i,b) |
33 | | * i=0 |
34 | | * |
35 | | * where: |
36 | | * |
37 | | * p(k) = exp(-ncp/2) (ncp/2)^k / k! |
38 | | * |
39 | | * B(a,b) = Gamma(a) * Gamma(b) / Gamma(a+b) |
40 | | * |
41 | | * |
42 | | * This can be computed efficiently by using the recursions: |
43 | | * |
44 | | * p(k+1) = ncp/2 / (k+1) * p(k) |
45 | | * |
46 | | * B(a+k+1,b) = (a+k)/(a+b+k) * B(a+k,b) |
47 | | * |
48 | | * The new algorithm first determines for which k the k-th term is maximal, |
49 | | * and then sums outwards to both sides from the 'mid'. |
50 | | */ |
51 | | |
52 | | #include "nmath.h" |
53 | | #include "dpq.h" |
54 | | |
55 | | double dnbeta(double x, double a, double b, double ncp, int give_log) |
56 | 0 | { |
57 | 0 | const static double eps = 1.e-15; |
58 | |
|
59 | 0 | #ifdef IEEE_754 |
60 | 0 | if (ISNAN(x) || ISNAN(a) || ISNAN(b) || ISNAN(ncp)) |
61 | 0 | return x + a + b + ncp; |
62 | 0 | #endif |
63 | 0 | if (ncp < 0 || a <= 0 || b <= 0) |
64 | 0 | ML_WARN_return_NAN; |
65 | |
|
66 | 0 | if (!R_FINITE(a) || !R_FINITE(b) || !R_FINITE(ncp)) |
67 | 0 | ML_WARN_return_NAN; |
68 | |
|
69 | 0 | if (x < 0 || x > 1) return(R_D__0); |
70 | 0 | if(ncp == 0) |
71 | 0 | return dbeta(x, a, b, give_log); |
72 | | |
73 | | /* Non-central Beta: New algorithm, starting with *largest* term : */ |
74 | 0 | double |
75 | 0 | ncp2 = ldexp(ncp, -1), // = 0.5 * ncp |
76 | 0 | dx2 = ncp2*x, |
77 | 0 | d = ldexp(dx2 - a - 1, -1), // = (...)/2 |
78 | 0 | D = d*d + dx2 * (a + b) - a; |
79 | 0 | int kMax; |
80 | 0 | if(D <= 0) { |
81 | 0 | kMax = 0; |
82 | 0 | } else { |
83 | 0 | D = ceil(d + sqrt(D)); |
84 | 0 | kMax = (D > 0) ? (int)D : 0; |
85 | 0 | } |
86 | |
|
87 | 0 | LDOUBLE sum, term, p_k, q; |
88 | | /* The starting "middle term" --- first look at it's log scale: */ |
89 | 0 | term = dbeta(x, a + kMax, b, /* log = */ TRUE); |
90 | 0 | p_k = dpois_raw(kMax, ncp2, TRUE); |
91 | 0 | if(x == 0. || !R_FINITE(term) || !R_FINITE((double)p_k)) /* if term = +Inf */ |
92 | 0 | return R_D_exp((double)(p_k + term)); |
93 | | |
94 | | /* Now if s_k := p_k * t_k {here = exp(p_k + term)} would underflow, |
95 | | * we should rather scale everything and re-scale at the end:*/ |
96 | | |
97 | 0 | p_k += term; /* = log(p_k) + log(t_k) == log(s_k) -- used at end to rescale */ |
98 | | /* mid = 1 = the rescaled value, instead of mid = exp(p_k); */ |
99 | | |
100 | | /* Now sum from the inside out */ |
101 | 0 | sum = term = 1. /* = mid term */; |
102 | | /* middle to the left */ |
103 | 0 | double k = kMax; |
104 | 0 | while(k > 0 && term > sum * eps) { |
105 | 0 | k--; |
106 | 0 | q = /* 1 / r_k = */ (k+1)*(k+a) / (k+a+b) / dx2; |
107 | 0 | term *= q; |
108 | 0 | sum += term; |
109 | 0 | } |
110 | | /* middle to the right */ |
111 | 0 | term = 1.; |
112 | 0 | k = kMax; |
113 | 0 | do { |
114 | 0 | q = /* r_{old k} = */ dx2 * (k+a+b) / (k+a) / (k+1); |
115 | 0 | k++; |
116 | 0 | term *= q; |
117 | 0 | sum += term; |
118 | 0 | } while (term > sum * eps); |
119 | |
|
120 | 0 | #ifdef HAVE_LONG_DOUBLE |
121 | 0 | return R_D_exp((double)(p_k + logl(sum))); |
122 | | #else |
123 | | return R_D_exp((double)(p_k + log(sum))); |
124 | | #endif |
125 | 0 | } |