|
Packit |
67cb25 |
/* specfunc/beta_inc.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Author: G. Jungman */
|
|
Packit |
67cb25 |
/* Modified for cdfs by Brian Gough, June 2003 */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_gamma.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
beta_cont_frac (const double a, const double b, const double x,
|
|
Packit |
67cb25 |
const double epsabs)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const unsigned int max_iter = 512; /* control iterations */
|
|
Packit |
67cb25 |
const double cutoff = 2.0 * GSL_DBL_MIN; /* control the zero cutoff */
|
|
Packit |
67cb25 |
unsigned int iter_count = 0;
|
|
Packit |
67cb25 |
double cf;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* standard initialization for continued fraction */
|
|
Packit |
67cb25 |
double num_term = 1.0;
|
|
Packit |
67cb25 |
double den_term = 1.0 - (a + b) * x / (a + 1.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (den_term) < cutoff)
|
|
Packit |
67cb25 |
den_term = GSL_NAN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
den_term = 1.0 / den_term;
|
|
Packit |
67cb25 |
cf = den_term;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
while (iter_count < max_iter)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const int k = iter_count + 1;
|
|
Packit |
67cb25 |
double coeff = k * (b - k) * x / (((a - 1.0) + 2 * k) * (a + 2 * k));
|
|
Packit |
67cb25 |
double delta_frac;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* first step */
|
|
Packit |
67cb25 |
den_term = 1.0 + coeff * den_term;
|
|
Packit |
67cb25 |
num_term = 1.0 + coeff / num_term;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (den_term) < cutoff)
|
|
Packit |
67cb25 |
den_term = GSL_NAN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (num_term) < cutoff)
|
|
Packit |
67cb25 |
num_term = GSL_NAN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
den_term = 1.0 / den_term;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
delta_frac = den_term * num_term;
|
|
Packit |
67cb25 |
cf *= delta_frac;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
coeff = -(a + k) * (a + b + k) * x / ((a + 2 * k) * (a + 2 * k + 1.0));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* second step */
|
|
Packit |
67cb25 |
den_term = 1.0 + coeff * den_term;
|
|
Packit |
67cb25 |
num_term = 1.0 + coeff / num_term;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (den_term) < cutoff)
|
|
Packit |
67cb25 |
den_term = GSL_NAN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (num_term) < cutoff)
|
|
Packit |
67cb25 |
num_term = GSL_NAN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
den_term = 1.0 / den_term;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
delta_frac = den_term * num_term;
|
|
Packit |
67cb25 |
cf *= delta_frac;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs (delta_frac - 1.0) < 2.0 * GSL_DBL_EPSILON)
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (cf * fabs (delta_frac - 1.0) < epsabs)
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
++iter_count;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (iter_count >= max_iter)
|
|
Packit |
67cb25 |
return GSL_NAN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return cf;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* The function beta_inc_AXPY(A,Y,a,b,x) computes A * beta_inc(a,b,x)
|
|
Packit |
67cb25 |
+ Y taking account of possible cancellations when using the
|
|
Packit |
67cb25 |
hypergeometric transformation beta_inc(a,b,x)=1-beta_inc(b,a,1-x).
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
It also adjusts the accuracy of beta_inc() to fit the overall
|
|
Packit |
67cb25 |
absolute error when A*beta_inc is added to Y. (e.g. if Y >>
|
|
Packit |
67cb25 |
A*beta_inc then the accuracy of beta_inc can be reduced) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
beta_inc_AXPY (const double A, const double Y,
|
|
Packit |
67cb25 |
const double a, const double b, const double x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (x == 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return A * 0 + Y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (x == 1.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return A * 1 + Y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (a > 1e5 && b < 10 && x > a / (a + b))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Handle asymptotic regime, large a, small b, x > peak [AS 26.5.17] */
|
|
Packit |
67cb25 |
double N = a + (b - 1.0) / 2.0;
|
|
Packit |
67cb25 |
return A * gsl_sf_gamma_inc_Q (b, -N * log (x)) + Y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (b > 1e5 && a < 10 && x < b / (a + b))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Handle asymptotic regime, small a, large b, x < peak [AS 26.5.17] */
|
|
Packit |
67cb25 |
double N = b + (a - 1.0) / 2.0;
|
|
Packit |
67cb25 |
return A * gsl_sf_gamma_inc_P (a, -N * log1p (-x)) + Y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ln_beta = gsl_sf_lnbeta (a, b);
|
|
Packit |
67cb25 |
double ln_pre = -ln_beta + a * log (x) + b * log1p (-x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double prefactor = exp (ln_pre);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x < (a + 1.0) / (a + b + 2.0))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Apply continued fraction directly. */
|
|
Packit |
67cb25 |
double epsabs = fabs (Y / (A * prefactor / a)) * GSL_DBL_EPSILON;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double cf = beta_cont_frac (a, b, x, epsabs);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return A * (prefactor * cf / a) + Y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Apply continued fraction after hypergeometric transformation. */
|
|
Packit |
67cb25 |
double epsabs =
|
|
Packit |
67cb25 |
fabs ((A + Y) / (A * prefactor / b)) * GSL_DBL_EPSILON;
|
|
Packit |
67cb25 |
double cf = beta_cont_frac (b, a, 1.0 - x, epsabs);
|
|
Packit |
67cb25 |
double term = prefactor * cf / b;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (A == -Y)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return -A * term;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return A * (1 - term) + Y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Direct series evaluation for testing purposes only */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
beta_series (const double a, const double b, const double x,
|
|
Packit |
67cb25 |
const double epsabs)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double f = x / (1 - x);
|
|
Packit |
67cb25 |
double c = (b - 1) / (a + 1) * f;
|
|
Packit |
67cb25 |
double s = 1;
|
|
Packit |
67cb25 |
double n = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
s += c;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
do
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
n++;
|
|
Packit |
67cb25 |
c *= -f * (2 + n - b) / (2 + n + a);
|
|
Packit |
67cb25 |
s += c;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
while (n < 512 && fabs (c) > GSL_DBL_EPSILON * fabs (s) + epsabs);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
s /= (1 - x);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|