diff options
Diffstat (limited to 'libm/float/incbif.c')
| -rw-r--r-- | libm/float/incbif.c | 197 | 
1 files changed, 197 insertions, 0 deletions
| diff --git a/libm/float/incbif.c b/libm/float/incbif.c new file mode 100644 index 000000000..4d8c0652e --- /dev/null +++ b/libm/float/incbif.c @@ -0,0 +1,197 @@ +/*							incbif() + * + *      Inverse of imcomplete beta integral + * + * + * + * SYNOPSIS: + * + * float a, b, x, y, incbif(); + * + * x = incbif( a, b, y ); + * + * + * + * DESCRIPTION: + * + * Given y, the function finds x such that + * + *  incbet( a, b, x ) = y. + * + * the routine performs up to 10 Newton iterations to find the + * root of incbet(a,b,x) - y = 0. + * + * + * ACCURACY: + * + *                      Relative error: + *                x     a,b + * arithmetic   domain  domain  # trials    peak       rms + *    IEEE      0,1     0,100     5000     2.8e-4    8.3e-6 + * + * Overflow and larger errors may occur for one of a or b near zero + *  and the other large. + */ + + +/* +Cephes Math Library Release 2.2:  July, 1992 +Copyright 1984, 1987, 1992 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + +#include <math.h> + +extern float MACHEPF, MINLOGF; + +#define fabsf(x) ( (x) < 0 ? -(x) : (x) ) + +#ifdef ANSIC +float incbetf(float, float, float); +float ndtrif(float), expf(float), logf(float), sqrtf(float), lgamf(float); +#else +float incbetf(); +float ndtrif(), expf(), logf(), sqrtf(), lgamf(); +#endif + +float incbif( float aaa, float bbb, float yyy0 ) +{ +float aa, bb, yy0, a, b, y0; +float d, y, x, x0, x1, lgm, yp, di; +int i, rflg; + + +aa = aaa; +bb = bbb; +yy0 = yyy0; +if( yy0 <= 0 ) +	return(0.0); +if( yy0 >= 1.0 ) +	return(1.0); + +/* approximation to inverse function */ + +yp = -ndtrif(yy0); + +if( yy0 > 0.5 ) +	{ +	rflg = 1; +	a = bb; +	b = aa; +	y0 = 1.0 - yy0; +	yp = -yp; +	} +else +	{ +	rflg = 0; +	a = aa; +	b = bb; +	y0 = yy0; +	} + + +if( (aa <= 1.0) || (bb <= 1.0) ) +	{ +	y = 0.5 * yp * yp; +	} +else +	{ +	lgm = (yp * yp - 3.0)* 0.16666666666666667; +	x0 = 2.0/( 1.0/(2.0*a-1.0)  +  1.0/(2.0*b-1.0) ); +	y = yp * sqrtf( x0 + lgm ) / x0 +		- ( 1.0/(2.0*b-1.0) - 1.0/(2.0*a-1.0) ) +		* (lgm + 0.833333333333333333 - 2.0/(3.0*x0)); +	y = 2.0 * y; +	if( y < MINLOGF ) +		{ +		x0 = 1.0; +		goto under; +		} +	} + +x = a/( a + b * expf(y) ); +y = incbetf( a, b, x ); +yp = (y - y0)/y0; +if( fabsf(yp) < 0.1 ) +	goto newt; + +/* Resort to interval halving if not close enough */ +x0 = 0.0; +x1 = 1.0; +di = 0.5; + +for( i=0; i<20; i++ ) +	{ +	if( i != 0 ) +		{ +		x = di * x1  + (1.0-di) * x0; +		y = incbetf( a, b, x ); +		yp = (y - y0)/y0; +		if( fabsf(yp) < 1.0e-3 ) +			goto newt; +		} + +	if( y < y0 ) +		{ +		x0 = x; +		di = 0.5; +		} +	else +		{ +		x1 = x; +		di *= di; +		if( di == 0.0 ) +			di = 0.5; +		} +	} + +if( x0 == 0.0 ) +	{ +under: +	mtherr( "incbif", UNDERFLOW ); +	goto done; +	} + +newt: + +x0 = x; +lgm = lgamf(a+b) - lgamf(a) - lgamf(b); + +for( i=0; i<10; i++ ) +	{ +/* compute the function at this point */ +	if( i != 0 ) +		y = incbetf(a,b,x0); +/* compute the derivative of the function at this point */ +	d = (a - 1.0) * logf(x0) + (b - 1.0) * logf(1.0-x0) + lgm; +	if( d < MINLOGF ) +		{ +		x0 = 0.0; +		goto under; +		} +	d = expf(d); +/* compute the step to the next approximation of x */ +	d = (y - y0)/d; +	x = x0; +	x0 = x0 - d; +	if( x0 <= 0.0 ) +		{ +		x0 = 0.0; +		goto under; +		} +	if( x0 >= 1.0 ) +		{ +		x0 = 1.0; +		goto under; +		} +	if( i < 2 ) +		continue; +	if( fabsf(d/x0) < 256.0 * MACHEPF ) +		goto done; +	} + +done: +if( rflg ) +	x0 = 1.0 - x0; +return( x0 ); +} | 
