[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 | /* |
---|
| 63 | Cephes Math Library Release 2.8: June, 2000 |
---|
| 64 | Copyright 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 |
---|
| 93 | extern double fabs ( double ); |
---|
| 94 | extern double pow ( double, double ); |
---|
| 95 | extern double round ( double ); |
---|
| 96 | extern double gamma ( double ); |
---|
| 97 | extern double log ( double ); |
---|
| 98 | extern double exp ( double ); |
---|
| 99 | extern double psi ( double ); |
---|
| 100 | static double hyt2f1(double, double, double, double, double *); |
---|
| 101 | static double hys2f1(double, double, double, double, double *); |
---|
| 102 | double hyp2f1(double, double, double, double); |
---|
| 103 | #else |
---|
| 104 | double fabs(), pow(), round(), gamma(), log(), exp(), psi(); |
---|
| 105 | static double hyt2f1(); |
---|
| 106 | static double hys2f1(); |
---|
| 107 | double hyp2f1(); |
---|
| 108 | #endif |
---|
| 109 | extern double MAXNUM, MACHEP; |
---|
| 110 | |
---|
| 111 | double hyp2f1( a, b, c, x ) |
---|
| 112 | double a, b, c, x; |
---|
| 113 | { |
---|
| 114 | double d, d1, d2, e; |
---|
| 115 | double p, q, r, s, y, ax; |
---|
| 116 | double ia, ib, ic, id, err; |
---|
| 117 | int flag, i, aid; |
---|
| 118 | |
---|
| 119 | err = 0.0; |
---|
| 120 | ax = fabs(x); |
---|
| 121 | s = 1.0 - x; |
---|
| 122 | flag = 0; |
---|
| 123 | ia = round(a); /* nearest integer to a */ |
---|
| 124 | ib = round(b); |
---|
| 125 | |
---|
| 126 | if( a <= 0 ) |
---|
| 127 | { |
---|
| 128 | if( fabs(a-ia) < EPS ) /* a is a negative integer */ |
---|
| 129 | flag |= 1; |
---|
| 130 | } |
---|
| 131 | |
---|
| 132 | if( b <= 0 ) |
---|
| 133 | { |
---|
| 134 | if( fabs(b-ib) < EPS ) /* b is a negative integer */ |
---|
| 135 | flag |= 2; |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | if( 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 | |
---|
| 154 | if( 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 | |
---|
| 168 | if( flag ) /* function is a polynomial */ |
---|
| 169 | goto hypok; |
---|
| 170 | |
---|
| 171 | if( ax > 1.0 ) /* series diverges */ |
---|
| 172 | goto hypdiv; |
---|
| 173 | |
---|
| 174 | p = c - a; |
---|
| 175 | ia = round(p); /* nearest integer to c-a */ |
---|
| 176 | if( (ia <= 0.0) && (fabs(p-ia) < EPS) ) /* negative int c - a */ |
---|
| 177 | flag |= 4; |
---|
| 178 | |
---|
| 179 | r = c - b; |
---|
| 180 | ib = round(r); /* nearest integer to c-b */ |
---|
| 181 | if( (ib <= 0.0) && (fabs(r-ib) < EPS) ) /* negative int c - b */ |
---|
| 182 | flag |= 8; |
---|
| 183 | |
---|
| 184 | d = c - a - b; |
---|
| 185 | id = round(d); /* nearest integer to d */ |
---|
| 186 | q = fabs(d-id); |
---|
| 187 | |
---|
| 188 | /* Thanks to Christian Burger <BURGER@DMRHRZ11.HRZ.Uni-Marburg.DE> |
---|
| 189 | * for reporting a bug here. */ |
---|
| 190 | if( 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 | */ |
---|
| 215 | if( 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 | |
---|
| 240 | if( flag & 12 ) |
---|
| 241 | goto hypf; /* negative integer c-a or c-b */ |
---|
| 242 | |
---|
| 243 | hypok: |
---|
| 244 | y = hyt2f1( a, b, c, x, &err ); |
---|
| 245 | |
---|
| 246 | |
---|
| 247 | hypdon: |
---|
| 248 | if( err > ETHRESH ) |
---|
| 249 | { |
---|
| 250 | mtherr( "hyp2f1", PLOSS ); |
---|
| 251 | /* printf( "Estimated err = %.2e\n", err ); */ |
---|
| 252 | } |
---|
| 253 | return(y); |
---|
| 254 | |
---|
| 255 | /* The transformation for c-a or c-b negative integer |
---|
| 256 | * AMS55 #15.3.3 |
---|
| 257 | */ |
---|
| 258 | hypf: |
---|
| 259 | y = pow( s, d ) * hys2f1( c-a, c-b, c, x, &err ); |
---|
| 260 | goto hypdon; |
---|
| 261 | |
---|
| 262 | /* The alarm exit */ |
---|
| 263 | hypdiv: |
---|
| 264 | mtherr( "hyp2f1", OVERFLOW ); |
---|
| 265 | return( MAXNUM ); |
---|
| 266 | } |
---|
| 267 | |
---|
| 268 | |
---|
| 269 | |
---|
| 270 | |
---|
| 271 | |
---|
| 272 | |
---|
| 273 | /* Apply transformations for |x| near 1 |
---|
| 274 | * then call the power series |
---|
| 275 | */ |
---|
| 276 | static double hyt2f1( a, b, c, x, loss ) |
---|
| 277 | double a, b, c, x; |
---|
| 278 | double *loss; |
---|
| 279 | { |
---|
| 280 | double p, q, r, s, t, y, d, err, err1; |
---|
| 281 | double ax, id, d1, d2, e, y1; |
---|
| 282 | int i, aid; |
---|
| 283 | |
---|
| 284 | err = 0.0; |
---|
| 285 | s = 1.0 - x; |
---|
| 286 | if( 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 | |
---|
| 297 | d = c - a - b; |
---|
| 298 | id = round(d); /* nearest integer to d */ |
---|
| 299 | |
---|
| 300 | if( x > 0.9 ) |
---|
| 301 | { |
---|
| 302 | if( 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 | } |
---|
| 324 | else |
---|
| 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 | } |
---|
| 384 | nosum: |
---|
| 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; |
---|
| 399 | psidon: |
---|
| 400 | goto done; |
---|
| 401 | } |
---|
| 402 | |
---|
| 403 | } |
---|
| 404 | |
---|
| 405 | /* Use defining power series if no special cases */ |
---|
| 406 | y = hys2f1( a, b, c, x, &err ); |
---|
| 407 | |
---|
| 408 | done: |
---|
| 409 | *loss = err; |
---|
| 410 | return(y); |
---|
| 411 | } |
---|
| 412 | |
---|
| 413 | |
---|
| 414 | |
---|
| 415 | |
---|
| 416 | |
---|
| 417 | /* Defining power series expansion of Gauss hypergeometric function */ |
---|
| 418 | |
---|
| 419 | static double hys2f1( a, b, c, x, loss ) |
---|
| 420 | double a, b, c, x; |
---|
| 421 | double *loss; /* estimates loss of significance */ |
---|
| 422 | { |
---|
| 423 | double f, g, h, k, m, s, u, umax; |
---|
| 424 | int i; |
---|
| 425 | |
---|
| 426 | i = 0; |
---|
| 427 | umax = 0.0; |
---|
| 428 | f = a; |
---|
| 429 | g = b; |
---|
| 430 | h = c; |
---|
| 431 | s = 1.0; |
---|
| 432 | u = 1.0; |
---|
| 433 | k = 0.0; |
---|
| 434 | do |
---|
| 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 | } |
---|
| 454 | while( fabs(u/s) > MACHEP ); |
---|
| 455 | |
---|
| 456 | /* return estimated relative error */ |
---|
| 457 | *loss = (MACHEP*umax)/fabs(s) + (MACHEP*i); |
---|
| 458 | |
---|
| 459 | return(s); |
---|
| 460 | } |
---|