source: sasview/src/sans/models/c_extension/cephes/hyp2f1.c @ 230f479

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 230f479 was 230f479, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Rename C source dir for models (minor updates)

  • Property mode set to 100644
File size: 8.1 KB
RevLine 
[230f479]1/*                                                      hyp2f1.c
2 *
3 *      Gauss hypergeometric function   F
4 *                                     2 1
5 *
6 *
7 * SYNOPSIS:
8 *
9 * double a, b, c, x, y, hyp2f1();
10 *
11 * y = hyp2f1( a, b, c, x );
12 *
13 *
14 * DESCRIPTION:
15 *
16 *
17 *  hyp2f1( a, b, c, x )  =   F ( a, b; c; x )
18 *                           2 1
19 *
20 *           inf.
21 *            -   a(a+1)...(a+k) b(b+1)...(b+k)   k+1
22 *   =  1 +   >   -----------------------------  x   .
23 *            -         c(c+1)...(c+k) (k+1)!
24 *          k = 0
25 *
26 *  Cases addressed are
27 *      Tests and escapes for negative integer a, b, or c
28 *      Linear transformation if c - a or c - b negative integer
29 *      Special case c = a or c = b
30 *      Linear transformation for  x near +1
31 *      Transformation for x < -0.5
32 *      Psi function expansion if x > 0.5 and c - a - b integer
33 *      Conditionally, a recurrence on c to make c-a-b > 0
34 *
35 * |x| > 1 is rejected.
36 *
37 * The parameters a, b, c are considered to be integer
38 * valued if they are within 1.0e-14 of the nearest integer
39 * (1.0e-13 for IEEE arithmetic).
40 *
41 * ACCURACY:
42 *
43 *
44 *               Relative error (-1 < x < 1):
45 * arithmetic   domain     # trials      peak         rms
46 *    IEEE      -1,7        230000      1.2e-11     5.2e-14
47 *
48 * Several special cases also tested with a, b, c in
49 * the range -7 to 7.
50 *
51 * ERROR MESSAGES:
52 *
53 * A "partial loss of precision" message is printed if
54 * the internally estimated relative error exceeds 1^-12.
55 * A "singularity" message is printed on overflow or
56 * in cases not addressed (such as x < -1).
57 */
58
59/*                                                      hyp2f1  */
60
61
62/*
63Cephes Math Library Release 2.8:  June, 2000
64Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
65*/
66
67
68#include "mconf.h"
69
70#ifdef DEC
71#define EPS 1.0e-14
72#define EPS2 1.0e-11
73#endif
74
75#ifdef IBMPC
76#define EPS 1.0e-13
77#define EPS2 1.0e-10
78#endif
79
80#ifdef MIEEE
81#define EPS 1.0e-13
82#define EPS2 1.0e-10
83#endif
84
85#ifdef UNK
86#define EPS 1.0e-13
87#define EPS2 1.0e-10
88#endif
89
90#define ETHRESH 1.0e-12
91
92#ifdef ANSIPROT
93extern double fabs ( double );
94extern double pow ( double, double );
95extern double round ( double );
96extern double gamma ( double );
97extern double log ( double );
98extern double exp ( double );
99extern double psi ( double );
100static double hyt2f1(double, double, double, double, double *);
101static double hys2f1(double, double, double, double, double *);
102double hyp2f1(double, double, double, double);
103#else
104double fabs(), pow(), round(), gamma(), log(), exp(), psi();
105static double hyt2f1();
106static double hys2f1();
107double hyp2f1();
108#endif
109extern double MAXNUM, MACHEP;
110
111double hyp2f1( a, b, c, x )
112double a, b, c, x;
113{
114double d, d1, d2, e;
115double p, q, r, s, y, ax;
116double ia, ib, ic, id, err;
117int flag, i, aid;
118
119err = 0.0;
120ax = fabs(x);
121s = 1.0 - x;
122flag = 0;
123ia = round(a); /* nearest integer to a */
124ib = round(b);
125
126if( a <= 0 )
127        {
128        if( fabs(a-ia) < EPS )          /* a is a negative integer */
129                flag |= 1;
130        }
131
132if( b <= 0 )
133        {
134        if( fabs(b-ib) < EPS )          /* b is a negative integer */
135                flag |= 2;
136        }
137
138if( ax < 1.0 )
139        {
140        if( fabs(b-c) < EPS )           /* b = c */
141                {
142                y = pow( s, -a );       /* s to the -a power */
143                goto hypdon;
144                }
145        if( fabs(a-c) < EPS )           /* a = c */
146                {
147                y = pow( s, -b );       /* s to the -b power */
148                goto hypdon;
149                }
150        }
151
152
153
154if( c <= 0.0 )
155        {
156        ic = round(c);  /* nearest integer to c */
157        if( fabs(c-ic) < EPS )          /* c is a negative integer */
158                {
159                /* check if termination before explosion */
160                if( (flag & 1) && (ia > ic) )
161                        goto hypok;
162                if( (flag & 2) && (ib > ic) )
163                        goto hypok;
164                goto hypdiv;
165                }
166        }
167
168if( flag )                      /* function is a polynomial */
169        goto hypok;
170
171if( ax > 1.0 )                  /* series diverges      */
172        goto hypdiv;
173
174p = c - a;
175ia = round(p); /* nearest integer to c-a */
176if( (ia <= 0.0) && (fabs(p-ia) < EPS) ) /* negative int c - a */
177        flag |= 4;
178
179r = c - b;
180ib = round(r); /* nearest integer to c-b */
181if( (ib <= 0.0) && (fabs(r-ib) < EPS) ) /* negative int c - b */
182        flag |= 8;
183
184d = c - a - b;
185id = round(d); /* nearest integer to d */
186q = fabs(d-id);
187
188/* Thanks to Christian Burger <BURGER@DMRHRZ11.HRZ.Uni-Marburg.DE>
189 * for reporting a bug here.  */
190if( fabs(ax-1.0) < EPS )                        /* |x| == 1.0   */
191        {
192        if( x > 0.0 )
193                {
194                if( flag & 12 ) /* negative int c-a or c-b */
195                        {
196                        if( d >= 0.0 )
197                                goto hypf;
198                        else
199                                goto hypdiv;
200                        }
201                if( d <= 0.0 )
202                        goto hypdiv;
203                y = gamma(c)*gamma(d)/(gamma(p)*gamma(r));
204                goto hypdon;
205                }
206
207        if( d <= -1.0 )
208                goto hypdiv;
209
210        }
211
212/* Conditionally make d > 0 by recurrence on c
213 * AMS55 #15.2.27
214 */
215if( d < 0.0 )
216        {
217/* Try the power series first */
218        y = hyt2f1( a, b, c, x, &err );
219        if( err < ETHRESH )
220                goto hypdon;
221/* Apply the recurrence if power series fails */
222        err = 0.0;
223        aid = 2 - id;
224        e = c + aid;
225        d2 = hyp2f1(a,b,e,x);
226        d1 = hyp2f1(a,b,e+1.0,x);
227        q = a + b + 1.0;
228        for( i=0; i<aid; i++ )
229                {
230                r = e - 1.0;
231                y = (e*(r-(2.0*e-q)*x)*d2 + (e-a)*(e-b)*x*d1)/(e*r*s);
232                e = r;
233                d1 = d2;
234                d2 = y;
235                }
236        goto hypdon;
237        }
238
239
240if( flag & 12 )
241        goto hypf; /* negative integer c-a or c-b */
242
243hypok:
244y = hyt2f1( a, b, c, x, &err );
245
246
247hypdon:
248if( err > ETHRESH )
249        {
250        mtherr( "hyp2f1", PLOSS );
251/*      printf( "Estimated err = %.2e\n", err ); */
252        }
253return(y);
254
255/* The transformation for c-a or c-b negative integer
256 * AMS55 #15.3.3
257 */
258hypf:
259y = pow( s, d ) * hys2f1( c-a, c-b, c, x, &err );
260goto hypdon;
261
262/* The alarm exit */
263hypdiv:
264mtherr( "hyp2f1", OVERFLOW );
265return( MAXNUM );
266}
267
268
269
270
271
272
273/* Apply transformations for |x| near 1
274 * then call the power series
275 */
276static double hyt2f1( a, b, c, x, loss )
277double a, b, c, x;
278double *loss;
279{
280double p, q, r, s, t, y, d, err, err1;
281double ax, id, d1, d2, e, y1;
282int i, aid;
283
284err = 0.0;
285s = 1.0 - x;
286if( x < -0.5 )
287        {
288        if( b > a )
289                y = pow( s, -a ) * hys2f1( a, c-b, c, -x/s, &err );
290
291        else
292                y = pow( s, -b ) * hys2f1( c-a, b, c, -x/s, &err );
293
294        goto done;
295        }
296
297d = c - a - b;
298id = round(d);  /* nearest integer to d */
299
300if( x > 0.9 )
301{
302if( fabs(d-id) > EPS ) /* test for integer c-a-b */
303        {
304/* Try the power series first */
305        y = hys2f1( a, b, c, x, &err );
306        if( err < ETHRESH )
307                goto done;
308/* If power series fails, then apply AMS55 #15.3.6 */
309        q = hys2f1( a, b, 1.0-d, s, &err );     
310        q *= gamma(d) /(gamma(c-a) * gamma(c-b));
311        r = pow(s,d) * hys2f1( c-a, c-b, d+1.0, s, &err1 );
312        r *= gamma(-d)/(gamma(a) * gamma(b));
313        y = q + r;
314
315        q = fabs(q); /* estimate cancellation error */
316        r = fabs(r);
317        if( q > r )
318                r = q;
319        err += err1 + (MACHEP*r)/y;
320
321        y *= gamma(c);
322        goto done;
323        }
324else
325        {
326/* Psi function expansion, AMS55 #15.3.10, #15.3.11, #15.3.12 */
327        if( id >= 0.0 )
328                {
329                e = d;
330                d1 = d;
331                d2 = 0.0;
332                aid = id;
333                }
334        else
335                {
336                e = -d;
337                d1 = 0.0;
338                d2 = d;
339                aid = -id;
340                }
341
342        ax = log(s);
343
344        /* sum for t = 0 */
345        y = psi(1.0) + psi(1.0+e) - psi(a+d1) - psi(b+d1) - ax;
346        y /= gamma(e+1.0);
347
348        p = (a+d1) * (b+d1) * s / gamma(e+2.0); /* Poch for t=1 */
349        t = 1.0;
350        do
351                {
352                r = psi(1.0+t) + psi(1.0+t+e) - psi(a+t+d1)
353                        - psi(b+t+d1) - ax;
354                q = p * r;
355                y += q;
356                p *= s * (a+t+d1) / (t+1.0);
357                p *= (b+t+d1) / (t+1.0+e);
358                t += 1.0;
359                }
360        while( fabs(q/y) > EPS );
361
362
363        if( id == 0.0 )
364                {
365                y *= gamma(c)/(gamma(a)*gamma(b));
366                goto psidon;
367                }
368
369        y1 = 1.0;
370
371        if( aid == 1 )
372                goto nosum;
373
374        t = 0.0;
375        p = 1.0;
376        for( i=1; i<aid; i++ )
377                {
378                r = 1.0-e+t;
379                p *= s * (a+t+d2) * (b+t+d2) / r;
380                t += 1.0;
381                p /= t;
382                y1 += p;
383                }
384nosum:
385        p = gamma(c);
386        y1 *= gamma(e) * p / (gamma(a+d1) * gamma(b+d1));
387
388        y *= p / (gamma(a+d2) * gamma(b+d2));
389        if( (aid & 1) != 0 )
390                y = -y;
391
392        q = pow( s, id );       /* s to the id power */
393        if( id > 0.0 )
394                y *= q;
395        else
396                y1 *= q;
397
398        y += y1;
399psidon:
400        goto done;
401        }
402
403}
404
405/* Use defining power series if no special cases */
406y = hys2f1( a, b, c, x, &err );
407
408done:
409*loss = err;
410return(y);
411}
412
413
414
415
416
417/* Defining power series expansion of Gauss hypergeometric function */
418
419static double hys2f1( a, b, c, x, loss )
420double a, b, c, x;
421double *loss; /* estimates loss of significance */
422{
423double f, g, h, k, m, s, u, umax;
424int i;
425
426i = 0;
427umax = 0.0;
428f = a;
429g = b;
430h = c;
431s = 1.0;
432u = 1.0;
433k = 0.0;
434do
435        {
436        if( fabs(h) < EPS )
437                {
438                *loss = 1.0;
439                return( MAXNUM );
440                }
441        m = k + 1.0;
442        u = u * ((f+k) * (g+k) * x / ((h+k) * m));
443        s += u;
444        k = fabs(u);  /* remember largest term summed */
445        if( k > umax )
446                umax = k;
447        k = m;
448        if( ++i > 10000 ) /* should never happen */
449                {
450                *loss = 1.0;
451                return(s);
452                }
453        }
454while( fabs(u/s) > MACHEP );
455
456/* return estimated relative error */
457*loss = (MACHEP*umax)/fabs(s) + (MACHEP*i);
458
459return(s);
460}
Note: See TracBrowser for help on using the repository browser.