~ubuntu-branches/ubuntu/saucy/python-scipy/saucy

« back to all changes in this revision

Viewing changes to scipy/special/cephes/incbi.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondrej Certik
  • Date: 2008-06-16 22:58:01 UTC
  • mfrom: (2.1.24 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080616225801-irdhrpcwiocfbcmt
Tags: 0.6.0-12
* The description updated to match the current SciPy (Closes: #489149).
* Standards-Version bumped to 3.8.0 (no action needed)
* Build-Depends: netcdf-dev changed to libnetcdf-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*                                                      incbi()
 
2
 *
 
3
 *      Inverse of imcomplete beta integral
 
4
 *
 
5
 *
 
6
 *
 
7
 * SYNOPSIS:
 
8
 *
 
9
 * double a, b, x, y, incbi();
 
10
 *
 
11
 * x = incbi( a, b, y );
 
12
 *
 
13
 *
 
14
 *
 
15
 * DESCRIPTION:
 
16
 *
 
17
 * Given y, the function finds x such that
 
18
 *
 
19
 *  incbet( a, b, x ) = y .
 
20
 *
 
21
 * The routine performs interval halving or Newton iterations to find the
 
22
 * root of incbet(a,b,x) - y = 0.
 
23
 *
 
24
 *
 
25
 * ACCURACY:
 
26
 *
 
27
 *                      Relative error:
 
28
 *                x     a,b
 
29
 * arithmetic   domain  domain  # trials    peak       rms
 
30
 *    IEEE      0,1    .5,10000   50000    5.8e-12   1.3e-13
 
31
 *    IEEE      0,1   .25,100    100000    1.8e-13   3.9e-15
 
32
 *    IEEE      0,1     0,5       50000    1.1e-12   5.5e-15
 
33
 *    VAX       0,1    .5,100     25000    3.5e-14   1.1e-15
 
34
 * With a and b constrained to half-integer or integer values:
 
35
 *    IEEE      0,1    .5,10000   50000    5.8e-12   1.1e-13
 
36
 *    IEEE      0,1    .5,100    100000    1.7e-14   7.9e-16
 
37
 * With a = .5, b constrained to half-integer or integer values:
 
38
 *    IEEE      0,1    .5,10000   10000    8.3e-11   1.0e-11
 
39
 */
 
40
 
 
41
 
 
42
/*
 
43
Cephes Math Library Release 2.4:  March,1996
 
44
Copyright 1984, 1996 by Stephen L. Moshier
 
45
*/
 
46
 
 
47
#include "mconf.h"
 
48
 
 
49
extern double MACHEP, MAXNUM, MAXLOG, MINLOG;
 
50
#ifndef ANSIPROT
 
51
double ndtri(), exp(), fabs(), log(), sqrt(), lgam(), incbet();
 
52
#endif
 
53
 
 
54
double incbi( aa, bb, yy0 )
 
55
double aa, bb, yy0;
 
56
{
 
57
double a, b, y0, d, y, x, x0, x1, lgm, yp, di, dithresh, yl, yh, xt;
 
58
int i, rflg, dir, nflg;
 
59
 
 
60
 
 
61
i = 0;
 
62
if( yy0 <= 0 )
 
63
        return(0.0);
 
64
if( yy0 >= 1.0 )
 
65
        return(1.0);
 
66
x0 = 0.0;
 
67
yl = 0.0;
 
68
x1 = 1.0;
 
69
yh = 1.0;
 
70
nflg = 0;
 
71
 
 
72
if( aa <= 1.0 || bb <= 1.0 )
 
73
        {
 
74
        dithresh = 1.0e-6;
 
75
        rflg = 0;
 
76
        a = aa;
 
77
        b = bb;
 
78
        y0 = yy0;
 
79
        x = a/(a+b);
 
80
        y = incbet( a, b, x );
 
81
        goto ihalve;
 
82
        }
 
83
else
 
84
        {
 
85
        dithresh = 1.0e-4;
 
86
        }
 
87
/* approximation to inverse function */
 
88
 
 
89
yp = -ndtri(yy0);
 
90
 
 
91
if( yy0 > 0.5 )
 
92
        {
 
93
        rflg = 1;
 
94
        a = bb;
 
95
        b = aa;
 
96
        y0 = 1.0 - yy0;
 
97
        yp = -yp;
 
98
        }
 
99
else
 
100
        {
 
101
        rflg = 0;
 
102
        a = aa;
 
103
        b = bb;
 
104
        y0 = yy0;
 
105
        }
 
106
 
 
107
lgm = (yp * yp - 3.0)/6.0;
 
108
x = 2.0/( 1.0/(2.0*a-1.0)  +  1.0/(2.0*b-1.0) );
 
109
d = yp * sqrt( x + lgm ) / x
 
110
        - ( 1.0/(2.0*b-1.0) - 1.0/(2.0*a-1.0) )
 
111
        * (lgm + 5.0/6.0 - 2.0/(3.0*x));
 
112
d = 2.0 * d;
 
113
if( d < MINLOG )
 
114
        {
 
115
        x = 1.0;
 
116
        goto under;
 
117
        }
 
118
x = a/( a + b * exp(d) );
 
119
y = incbet( a, b, x );
 
120
yp = (y - y0)/y0;
 
121
if( fabs(yp) < 0.2 )
 
122
        goto newt;
 
123
 
 
124
/* Resort to interval halving if not close enough. */
 
125
ihalve:
 
126
 
 
127
dir = 0;
 
128
di = 0.5;
 
129
for( i=0; i<100; i++ )
 
130
        {
 
131
        if( i != 0 )
 
132
                {
 
133
                x = x0  +  di * (x1 - x0);
 
134
                if( x == 1.0 )
 
135
                        x = 1.0 - MACHEP;
 
136
                if( x == 0.0 )
 
137
                        {
 
138
                        di = 0.5;
 
139
                        x = x0  +  di * (x1 - x0);
 
140
                        if( x == 0.0 )
 
141
                                goto under;
 
142
                        }
 
143
                y = incbet( a, b, x );
 
144
                yp = (x1 - x0)/(x1 + x0);
 
145
                if( fabs(yp) < dithresh )
 
146
                        goto newt;
 
147
                yp = (y-y0)/y0;
 
148
                if( fabs(yp) < dithresh )
 
149
                        goto newt;
 
150
                }
 
151
        if( y < y0 )
 
152
                {
 
153
                x0 = x;
 
154
                yl = y;
 
155
                if( dir < 0 )
 
156
                        {
 
157
                        dir = 0;
 
158
                        di = 0.5;
 
159
                        }
 
160
                else if( dir > 3 )
 
161
                        di = 1.0 - (1.0 - di) * (1.0 - di);
 
162
                else if( dir > 1 )
 
163
                        di = 0.5 * di + 0.5; 
 
164
                else
 
165
                        di = (y0 - y)/(yh - yl);
 
166
                dir += 1;
 
167
                if( x0 > 0.75 )
 
168
                        {
 
169
                        if( rflg == 1 )
 
170
                                {
 
171
                                rflg = 0;
 
172
                                a = aa;
 
173
                                b = bb;
 
174
                                y0 = yy0;
 
175
                                }
 
176
                        else
 
177
                                {
 
178
                                rflg = 1;
 
179
                                a = bb;
 
180
                                b = aa;
 
181
                                y0 = 1.0 - yy0;
 
182
                                }
 
183
                        x = 1.0 - x;
 
184
                        y = incbet( a, b, x );
 
185
                        x0 = 0.0;
 
186
                        yl = 0.0;
 
187
                        x1 = 1.0;
 
188
                        yh = 1.0;
 
189
                        goto ihalve;
 
190
                        }
 
191
                }
 
192
        else
 
193
                {
 
194
                x1 = x;
 
195
                if( rflg == 1 && x1 < MACHEP )
 
196
                        {
 
197
                        x = 0.0;
 
198
                        goto done;
 
199
                        }
 
200
                yh = y;
 
201
                if( dir > 0 )
 
202
                        {
 
203
                        dir = 0;
 
204
                        di = 0.5;
 
205
                        }
 
206
                else if( dir < -3 )
 
207
                        di = di * di;
 
208
                else if( dir < -1 )
 
209
                        di = 0.5 * di;
 
210
                else
 
211
                        di = (y - y0)/(yh - yl);
 
212
                dir -= 1;
 
213
                }
 
214
        }
 
215
mtherr( "incbi", PLOSS );
 
216
if( x0 >= 1.0 )
 
217
        {
 
218
        x = 1.0 - MACHEP;
 
219
        goto done;
 
220
        }
 
221
if( x <= 0.0 )
 
222
        {
 
223
under:
 
224
        mtherr( "incbi", UNDERFLOW );
 
225
        x = 0.0;
 
226
        goto done;
 
227
        }
 
228
 
 
229
newt:
 
230
 
 
231
if( nflg )
 
232
        goto done;
 
233
nflg = 1;
 
234
lgm = lgam(a+b) - lgam(a) - lgam(b);
 
235
 
 
236
for( i=0; i<8; i++ )
 
237
        {
 
238
        /* Compute the function at this point. */
 
239
        if( i != 0 )
 
240
                y = incbet(a,b,x);
 
241
        if( y < yl )
 
242
                {
 
243
                x = x0;
 
244
                y = yl;
 
245
                }
 
246
        else if( y > yh )
 
247
                {
 
248
                x = x1;
 
249
                y = yh;
 
250
                }
 
251
        else if( y < y0 )
 
252
                {
 
253
                x0 = x;
 
254
                yl = y;
 
255
                }
 
256
        else
 
257
                {
 
258
                x1 = x;
 
259
                yh = y;
 
260
                }
 
261
        if( x == 1.0 || x == 0.0 )
 
262
                break;
 
263
        /* Compute the derivative of the function at this point. */
 
264
        d = (a - 1.0) * log(x) + (b - 1.0) * log(1.0-x) + lgm;
 
265
        if( d < MINLOG )
 
266
                goto done;
 
267
        if( d > MAXLOG )
 
268
                break;
 
269
        d = exp(d);
 
270
        /* Compute the step to the next approximation of x. */
 
271
        d = (y - y0)/d;
 
272
        xt = x - d;
 
273
        if( xt <= x0 )
 
274
                {
 
275
                y = (x - x0) / (x1 - x0);
 
276
                xt = x0 + 0.5 * y * (x - x0);
 
277
                if( xt <= 0.0 )
 
278
                        break;
 
279
                }
 
280
        if( xt >= x1 )
 
281
                {
 
282
                y = (x1 - x) / (x1 - x0);
 
283
                xt = x1 - 0.5 * y * (x1 - x);
 
284
                if( xt >= 1.0 )
 
285
                        break;
 
286
                }
 
287
        x = xt;
 
288
        if( fabs(d/x) < 128.0 * MACHEP )
 
289
                goto done;
 
290
        }
 
291
/* Did not converge.  */
 
292
dithresh = 256.0 * MACHEP;
 
293
goto ihalve;
 
294
 
 
295
done:
 
296
 
 
297
if( rflg )
 
298
        {
 
299
        if( x <= MACHEP )
 
300
                x = 1.0 - MACHEP;
 
301
        else
 
302
                x = 1.0 - x;
 
303
        }
 
304
return( x );
 
305
}