hyp2f1.c
Go to the documentation of this file.
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 AMS 15.3.7 transformation applied (Travis Oliphant)
36  * valid for b,a,c,(b-a) != integer and (c-a),(c-b) != negative integer
37  *
38  * x >= 1 is rejected (unless special cases are present)
39  *
40  * The parameters a, b, c are considered to be integer
41  * valued if they are within 1.0e-14 of the nearest integer
42  * (1.0e-13 for IEEE arithmetic).
43  *
44  * ACCURACY:
45  *
46  *
47  * Relative error (-1 < x < 1):
48  * arithmetic domain # trials peak rms
49  * IEEE -1,7 230000 1.2e-11 5.2e-14
50  *
51  * Several special cases also tested with a, b, c in
52  * the range -7 to 7.
53  *
54  * ERROR MESSAGES:
55  *
56  * A "partial loss of precision" message is printed if
57  * the internally estimated relative error exceeds 1^-12.
58  * A "singularity" message is printed on overflow or
59  * in cases not addressed (such as x < -1).
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 #include <assert.h>
68 #include <math.h>
69 #include <stdlib.h>
70 
71 #include "mconf.h"
72 
73 #define EPS 1.0e-13
74 #define EPS2 1.0e-10
75 
76 #define ETHRESH 1.0e-12
77 
78 #define MAX_ITERATIONS 10000
79 
80 extern double MACHEP;
81 
82 /* hys2f1 and hyp2f1ra depend on each other, so we need this prototype */
83 static double hyp2f1ra(double a, double b, double c, double x, double *loss);
84 
85 /* Defining power series expansion of Gauss hypergeometric function */
86 /* The `loss` parameter estimates loss of significance */
87 static double hys2f1(double a, double b, double c, double x, double *loss) {
88  double f, g, h, k, m, s, u, umax;
89  int i;
90  int ib, intflag = 0;
91 
92  if (fabs(b) > fabs(a)) {
93  /* Ensure that |a| > |b| ... */
94  f = b;
95  b = a;
96  a = f;
97  }
98 
99  ib = round(b);
100 
101  if (fabs(b - ib) < EPS && ib <= 0 && fabs(b) < fabs(a)) {
102  /* .. except when `b` is a smaller negative integer */
103  f = b;
104  b = a;
105  a = f;
106  intflag = 1;
107  }
108 
109  if ((fabs(a) > fabs(c) + 1 || intflag) && fabs(c - a) > 2 && fabs(a) > 2) {
110  /* |a| >> |c| implies that large cancellation error is to be expected.
111  *
112  * We try to reduce it with the recurrence relations
113  */
114  return hyp2f1ra(a, b, c, x, loss);
115  }
116 
117  i = 0;
118  umax = 0.0;
119  f = a;
120  g = b;
121  h = c;
122  s = 1.0;
123  u = 1.0;
124  k = 0.0;
125  do {
126  if (fabs(h) < EPS) {
127  *loss = 1.0;
128  return INFINITY;
129  }
130  m = k + 1.0;
131  u = u * ((f + k) * (g + k) * x / ((h + k) * m));
132  s += u;
133  k = fabs(u); /* remember largest term summed */
134  if (k > umax) umax = k;
135  k = m;
136  if (++i > MAX_ITERATIONS) { /* should never happen */
137  *loss = 1.0;
138  return (s);
139  }
140  } while (s == 0 || fabs(u / s) > MACHEP);
141 
142  /* return estimated relative error */
143  *loss = (MACHEP * umax) / fabs(s) + (MACHEP * i);
144 
145  return (s);
146 }
147 
148 /* Apply transformations for |x| near 1 then call the power series */
149 static double hyt2f1(double a, double b, double c, double x, double *loss) {
150  double p, q, r, s, t, y, w, d, err, err1;
151  double ax, id, d1, d2, e, y1;
152  int i, aid, sign;
153 
154  int ia, ib, neg_int_a = 0, neg_int_b = 0;
155 
156  ia = round(a);
157  ib = round(b);
158 
159  if (a <= 0 && fabs(a - ia) < EPS) { /* a is a negative integer */
160  neg_int_a = 1;
161  }
162 
163  if (b <= 0 && fabs(b - ib) < EPS) { /* b is a negative integer */
164  neg_int_b = 1;
165  }
166 
167  err = 0.0;
168  s = 1.0 - x;
169  if (x < -0.5 && !(neg_int_a || neg_int_b)) {
170  if (b > a)
171  y = pow(s, -a) * hys2f1(a, c - b, c, -x / s, &err);
172 
173  else
174  y = pow(s, -b) * hys2f1(c - a, b, c, -x / s, &err);
175 
176  goto done;
177  }
178 
179  d = c - a - b;
180  id = round(d); /* nearest integer to d */
181 
182  if (x > 0.9 && !(neg_int_a || neg_int_b)) {
183  if (fabs(d - id) > EPS) {
184  int sgngam;
185 
186  /* test for integer c-a-b */
187  /* Try the power series first */
188  y = hys2f1(a, b, c, x, &err);
189  if (err < ETHRESH) goto done;
190  /* If power series fails, then apply AMS55 #15.3.6 */
191  q = hys2f1(a, b, 1.0 - d, s, &err);
192  sign = 1;
193  w = lgam_sgn(d, &sgngam);
194  sign *= sgngam;
195  w -= lgam_sgn(c - a, &sgngam);
196  sign *= sgngam;
197  w -= lgam_sgn(c - b, &sgngam);
198  sign *= sgngam;
199  q *= sign * exp(w);
200  r = pow(s, d) * hys2f1(c - a, c - b, d + 1.0, s, &err1);
201  sign = 1;
202  w = lgam_sgn(-d, &sgngam);
203  sign *= sgngam;
204  w -= lgam_sgn(a, &sgngam);
205  sign *= sgngam;
206  w -= lgam_sgn(b, &sgngam);
207  sign *= sgngam;
208  r *= sign * exp(w);
209  y = q + r;
210 
211  q = fabs(q); /* estimate cancellation error */
212  r = fabs(r);
213  if (q > r) r = q;
214  err += err1 + (MACHEP * r) / y;
215 
216  y *= gamma(c);
217  goto done;
218  } else {
219  /* Psi function expansion, AMS55 #15.3.10, #15.3.11, #15.3.12
220  *
221  * Although AMS55 does not explicitly state it, this expansion fails
222  * for negative integer a or b, since the psi and Gamma functions
223  * involved have poles.
224  */
225 
226  if (id >= 0.0) {
227  e = d;
228  d1 = d;
229  d2 = 0.0;
230  aid = id;
231  } else {
232  e = -d;
233  d1 = 0.0;
234  d2 = d;
235  aid = -id;
236  }
237 
238  ax = log(s);
239 
240  /* sum for t = 0 */
241  y = psi(1.0) + psi(1.0 + e) - psi(a + d1) - psi(b + d1) - ax;
242  y /= gamma(e + 1.0);
243 
244  p = (a + d1) * (b + d1) * s / gamma(e + 2.0); /* Poch for t=1 */
245  t = 1.0;
246  do {
247  r = psi(1.0 + t) + psi(1.0 + t + e) - psi(a + t + d1) -
248  psi(b + t + d1) - ax;
249  q = p * r;
250  y += q;
251  p *= s * (a + t + d1) / (t + 1.0);
252  p *= (b + t + d1) / (t + 1.0 + e);
253  t += 1.0;
254  if (t > MAX_ITERATIONS) { /* should never happen */
255  sf_error("hyp2f1", SF_ERROR_SLOW, NULL);
256  *loss = 1.0;
257  return NAN;
258  }
259  } while (y == 0 || fabs(q / y) > EPS);
260 
261  if (id == 0.0) {
262  y *= gamma(c) / (gamma(a) * gamma(b));
263  goto psidon;
264  }
265 
266  y1 = 1.0;
267 
268  if (aid == 1) goto nosum;
269 
270  t = 0.0;
271  p = 1.0;
272  for (i = 1; i < aid; i++) {
273  r = 1.0 - e + t;
274  p *= s * (a + t + d2) * (b + t + d2) / r;
275  t += 1.0;
276  p /= t;
277  y1 += p;
278  }
279  nosum:
280  p = gamma(c);
281  y1 *= gamma(e) * p / (gamma(a + d1) * gamma(b + d1));
282 
283  y *= p / (gamma(a + d2) * gamma(b + d2));
284  if ((aid & 1) != 0) y = -y;
285 
286  q = pow(s, id); /* s to the id power */
287  if (id > 0.0)
288  y *= q;
289  else
290  y1 *= q;
291 
292  y += y1;
293  psidon:
294  goto done;
295  }
296  }
297 
298  /* Use defining power series if no special cases */
299  y = hys2f1(a, b, c, x, &err);
300 
301 done:
302  *loss = err;
303  return (y);
304 }
305 
306 /*
307  15.4.2 Abramowitz & Stegun.
308 */
309 static double hyp2f1_neg_c_equal_bc(double a, double b, double x) {
310  double k;
311  double collector = 1;
312  double sum = 1;
313  double collector_max = 1;
314 
315  if (!(fabs(b) < 1e5)) {
316  return NAN;
317  }
318 
319  for (k = 1; k <= -b; k++) {
320  collector *= (a + k - 1) * x / k;
321  collector_max = fmax(fabs(collector), collector_max);
322  sum += collector;
323  }
324 
325  if (1e-16 * (1 + collector_max / fabs(sum)) > 1e-7) {
326  return NAN;
327  }
328 
329  return sum;
330 }
331 
332 double hyp2f1(double a, double b, double c, double x) {
333  double d, d1, d2, e;
334  double p, q, r, s, y, ax;
335  double ia, ib, ic, id, err;
336  double t1;
337  int i, aid;
338  int neg_int_a = 0, neg_int_b = 0;
339  int neg_int_ca_or_cb = 0;
340 
341  err = 0.0;
342  ax = fabs(x);
343  s = 1.0 - x;
344  ia = round(a); /* nearest integer to a */
345  ib = round(b);
346 
347  if (x == 0.0) {
348  return 1.0;
349  }
350 
351  d = c - a - b;
352  id = round(d);
353 
354  if ((a == 0 || b == 0) && c != 0) {
355  return 1.0;
356  }
357 
358  if (a <= 0 && fabs(a - ia) < EPS) { /* a is a negative integer */
359  neg_int_a = 1;
360  }
361 
362  if (b <= 0 && fabs(b - ib) < EPS) { /* b is a negative integer */
363  neg_int_b = 1;
364  }
365 
366  if (d <= -1 && !(fabs(d - id) > EPS && s < 0) && !(neg_int_a || neg_int_b)) {
367  return pow(s, d) * hyp2f1(c - a, c - b, c, x);
368  }
369  if (d <= 0 && x == 1 && !(neg_int_a || neg_int_b)) goto hypdiv;
370 
371  if (ax < 1.0 || x == -1.0) {
372  /* 2F1(a,b;b;x) = (1-x)**(-a) */
373  if (fabs(b - c) < EPS) { /* b = c */
374  if (neg_int_b) {
375  y = hyp2f1_neg_c_equal_bc(a, b, x);
376  } else {
377  y = pow(s, -a); /* s to the -a power */
378  }
379  goto hypdon;
380  }
381  if (fabs(a - c) < EPS) { /* a = c */
382  y = pow(s, -b); /* s to the -b power */
383  goto hypdon;
384  }
385  }
386 
387  if (c <= 0.0) {
388  ic = round(c); /* nearest integer to c */
389  if (fabs(c - ic) < EPS) { /* c is a negative integer */
390  /* check if termination before explosion */
391  if (neg_int_a && (ia > ic)) goto hypok;
392  if (neg_int_b && (ib > ic)) goto hypok;
393  goto hypdiv;
394  }
395  }
396 
397  if (neg_int_a || neg_int_b) /* function is a polynomial */
398  goto hypok;
399 
400  t1 = fabs(b - a);
401  if (x < -2.0 && fabs(t1 - round(t1)) > EPS) {
402  /* This transform has a pole for b-a integer, and
403  * may produce large cancellation errors for |1/x| close 1
404  */
405  p = hyp2f1(a, 1 - c + a, 1 - b + a, 1.0 / x);
406  q = hyp2f1(b, 1 - c + b, 1 - a + b, 1.0 / x);
407  p *= pow(-x, -a);
408  q *= pow(-x, -b);
409  t1 = gamma(c);
410  s = t1 * gamma(b - a) / (gamma(b) * gamma(c - a));
411  y = t1 * gamma(a - b) / (gamma(a) * gamma(c - b));
412  return s * p + y * q;
413  } else if (x < -1.0) {
414  if (fabs(a) < fabs(b)) {
415  return pow(s, -a) * hyp2f1(a, c - b, c, x / (x - 1));
416  } else {
417  return pow(s, -b) * hyp2f1(b, c - a, c, x / (x - 1));
418  }
419  }
420 
421  if (ax > 1.0) /* series diverges */
422  goto hypdiv;
423 
424  p = c - a;
425  ia = round(p); /* nearest integer to c-a */
426  if ((ia <= 0.0) && (fabs(p - ia) < EPS)) /* negative int c - a */
427  neg_int_ca_or_cb = 1;
428 
429  r = c - b;
430  ib = round(r); /* nearest integer to c-b */
431  if ((ib <= 0.0) && (fabs(r - ib) < EPS)) /* negative int c - b */
432  neg_int_ca_or_cb = 1;
433 
434  id = round(d); /* nearest integer to d */
435  q = fabs(d - id);
436 
437  /* Thanks to Christian Burger <BURGER@DMRHRZ11.HRZ.Uni-Marburg.DE>
438  * for reporting a bug here. */
439  if (fabs(ax - 1.0) < EPS) { /* |x| == 1.0 */
440  if (x > 0.0) {
441  if (neg_int_ca_or_cb) {
442  if (d >= 0.0)
443  goto hypf;
444  else
445  goto hypdiv;
446  }
447  if (d <= 0.0) goto hypdiv;
448  y = gamma(c) * gamma(d) / (gamma(p) * gamma(r));
449  goto hypdon;
450  }
451  if (d <= -1.0) goto hypdiv;
452  }
453 
454  /* Conditionally make d > 0 by recurrence on c
455  * AMS55 #15.2.27
456  */
457  if (d < 0.0) {
458  /* Try the power series first */
459  y = hyt2f1(a, b, c, x, &err);
460  if (err < ETHRESH) goto hypdon;
461  /* Apply the recurrence if power series fails */
462  err = 0.0;
463  aid = 2 - id;
464  e = c + aid;
465  d2 = hyp2f1(a, b, e, x);
466  d1 = hyp2f1(a, b, e + 1.0, x);
467  q = a + b + 1.0;
468  for (i = 0; i < aid; i++) {
469  r = e - 1.0;
470  y = (e * (r - (2.0 * e - q) * x) * d2 + (e - a) * (e - b) * x * d1) /
471  (e * r * s);
472  e = r;
473  d1 = d2;
474  d2 = y;
475  }
476  goto hypdon;
477  }
478 
479  if (neg_int_ca_or_cb) goto hypf; /* negative integer c-a or c-b */
480 
481 hypok:
482  y = hyt2f1(a, b, c, x, &err);
483 
484 hypdon:
485  if (err > ETHRESH) {
486  sf_error("hyp2f1", SF_ERROR_LOSS, NULL);
487  /* printf( "Estimated err = %.2e\n", err ); */
488  }
489  return (y);
490 
491  /* The transformation for c-a or c-b negative integer
492  * AMS55 #15.3.3
493  */
494 hypf:
495  y = pow(s, d) * hys2f1(c - a, c - b, c, x, &err);
496  goto hypdon;
497 
498  /* The alarm exit */
499 hypdiv:
500  sf_error("hyp2f1", SF_ERROR_OVERFLOW, NULL);
501  return INFINITY;
502 }
503 
504 /*
505  * Evaluate hypergeometric function by two-term recurrence in `a`.
506  *
507  * This avoids some of the loss of precision in the strongly alternating
508  * hypergeometric series, and can be used to reduce the `a` and `b` parameters
509  * to smaller values.
510  *
511  * AMS55 #15.2.10
512  */
513 static double hyp2f1ra(double a, double b, double c, double x, double *loss) {
514  double f2, f1, f0;
515  int n;
516  double t, err, da;
517 
518  /* Don't cross c or zero */
519  if ((c < 0 && a <= c) || (c >= 0 && a >= c)) {
520  da = round(a - c);
521  } else {
522  da = round(a);
523  }
524  t = a - da;
525 
526  *loss = 0;
527 
528  assert(da != 0);
529 
530  if (fabs(da) > MAX_ITERATIONS) {
531  /* Too expensive to compute this value, so give up */
532  sf_error("hyp2f1", SF_ERROR_NO_RESULT, NULL);
533  *loss = 1.0;
534  return NAN;
535  }
536 
537  if (da < 0) {
538  /* Recurse down */
539  f2 = 0;
540  f1 = hys2f1(t, b, c, x, &err);
541  *loss += err;
542  f0 = hys2f1(t - 1, b, c, x, &err);
543  *loss += err;
544  t -= 1;
545  for (n = 1; n < -da; ++n) {
546  f2 = f1;
547  f1 = f0;
548  f0 = -(2 * t - c - t * x + b * x) / (c - t) * f1 -
549  t * (x - 1) / (c - t) * f2;
550  t -= 1;
551  }
552  } else {
553  /* Recurse up */
554  f2 = 0;
555  f1 = hys2f1(t, b, c, x, &err);
556  *loss += err;
557  f0 = hys2f1(t + 1, b, c, x, &err);
558  *loss += err;
559  t += 1;
560  for (n = 1; n < da; ++n) {
561  f2 = f1;
562  f1 = f0;
563  f0 = -((2 * t - c - t * x + b * x) * f1 + (c - t) * f2) / (t * (x - 1));
564  t += 1;
565  }
566  }
567 
568  return f0;
569 }
w
RowVector3d w
Definition: Matrix_resize_int.cpp:3
hyp2f1_neg_c_equal_bc
static double hyp2f1_neg_c_equal_bc(double a, double b, double x)
Definition: hyp2f1.c:309
test_constructor::f1
auto f1
Definition: testHybridNonlinearFactor.cpp:56
psi
double psi(double x)
Definition: psi.c:146
s
RealScalar s
Definition: level1_cplx_impl.h:126
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
d
static const double d[K][N]
Definition: igam.h:11
hyp2f1ra
static double hyp2f1ra(double a, double b, double c, double x, double *loss)
Definition: hyp2f1.c:513
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
b
Scalar * b
Definition: benchVecAdd.cpp:17
SF_ERROR_NO_RESULT
@ SF_ERROR_NO_RESULT
Definition: sf_error.h:15
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
sign
const EIGEN_DEVICE_FUNC SignReturnType sign() const
Definition: ArrayCwiseUnaryOps.h:219
SF_ERROR_OVERFLOW
@ SF_ERROR_OVERFLOW
Definition: sf_error.h:12
ETHRESH
#define ETHRESH
Definition: hyp2f1.c:76
f2
double f2(const Vector2 &x)
Definition: testNumericalDerivative.cpp:56
log
const EIGEN_DEVICE_FUNC LogReturnType log() const
Definition: ArrayCwiseUnaryOps.h:128
exp
const EIGEN_DEVICE_FUNC ExpReturnType exp() const
Definition: ArrayCwiseUnaryOps.h:97
h
const double h
Definition: testSimpleHelicopter.cpp:19
SF_ERROR_SLOW
@ SF_ERROR_SLOW
Definition: sf_error.h:13
boost::multiprecision::fabs
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:119
n
int n
Definition: BiCGSTAB_simple.cpp:1
lgam_sgn
double lgam_sgn(double x, int *sign)
Definition: gamma.c:281
id
static const Similarity3 id
Definition: testSimilarity3.cpp:44
y1
double y1(double x)
Definition: j1.c:199
test_constructor::f0
auto f0
Definition: testHybridNonlinearFactor.cpp:55
Eigen::numext::q
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:1984
hys2f1
static double hys2f1(double a, double b, double c, double x, double *loss)
Definition: hyp2f1.c:87
round
double round(double x)
Definition: round.c:38
m
Matrix3f m
Definition: AngleAxis_mimic_euler.cpp:1
hyp2f1
double hyp2f1(double a, double b, double c, double x)
Definition: hyp2f1.c:332
gamma
#define gamma
Definition: mconf.h:85
hyt2f1
static double hyt2f1(double a, double b, double c, double x, double *loss)
Definition: hyp2f1.c:149
g
void g(const string &key, int i)
Definition: testBTree.cpp:41
y
Scalar * y
Definition: level1_cplx_impl.h:124
tree::f
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Definition: testExpression.cpp:218
test_docs.d2
d2
Definition: test_docs.py:29
EPS
#define EPS
Definition: hyp2f1.c:73
Eigen::ArrayBase::pow
const Eigen::CwiseBinaryOp< Eigen::internal::scalar_pow_op< typename Derived::Scalar, typename ExponentDerived::Scalar >, const Derived, const ExponentDerived > pow(const Eigen::ArrayBase< Derived > &x, const Eigen::ArrayBase< ExponentDerived > &exponents)
Definition: GlobalFunctions.h:143
a
ArrayXXi a
Definition: Array_initializer_list_23_cxx11.cpp:1
mconf.h
MAX_ITERATIONS
#define MAX_ITERATIONS
Definition: hyp2f1.c:78
Eigen::bfloat16_impl::fmax
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 fmax(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:587
p
float * p
Definition: Tutorial_Map_using.cpp:9
MACHEP
double MACHEP
Definition: const.c:54
sf_error
void sf_error(const char *func_name, sf_error_t code, const char *fmt,...)
Definition: sf_error.c:41
NULL
#define NULL
Definition: ccolamd.c:609
align_3::t
Point2 t(10, 10)
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
SF_ERROR_LOSS
@ SF_ERROR_LOSS
Definition: sf_error.h:14


gtsam
Author(s):
autogenerated on Fri Nov 1 2024 03:32:43