@@ -240,21 +240,25 @@ BOOST_MATH_GPU_ENABLED T ibeta_power_terms(T a,
240
240
T c = a + b;
241
241
242
242
// combine power terms with Lanczos approximation:
243
- T agh = static_cast <T>(a + Lanczos::g () - 0 .5f );
244
- T bgh = static_cast <T>(b + Lanczos::g () - 0 .5f );
245
- T cgh = static_cast <T>(c + Lanczos::g () - 0 .5f );
243
+ T gh = Lanczos::g () - 0 .5f ;
244
+ T agh = static_cast <T>(a + gh);
245
+ T bgh = static_cast <T>(b + gh);
246
+ T cgh = static_cast <T>(c + gh);
246
247
if ((a < tools::min_value<T>()) || (b < tools::min_value<T>()))
247
248
result = 0 ; // denominator overflows in this case
248
249
else
249
250
result = Lanczos::lanczos_sum_expG_scaled (c) / (Lanczos::lanczos_sum_expG_scaled (a) * Lanczos::lanczos_sum_expG_scaled (b));
251
+ BOOST_MATH_INSTRUMENT_VARIABLE (result);
250
252
result *= prefix;
253
+ BOOST_MATH_INSTRUMENT_VARIABLE (result);
251
254
// combine with the leftover terms from the Lanczos approximation:
252
255
result *= sqrt (bgh / boost::math::constants::e<T>());
253
256
result *= sqrt (agh / cgh);
257
+ BOOST_MATH_INSTRUMENT_VARIABLE (result);
254
258
255
259
// l1 and l2 are the base of the exponents minus one:
256
- T l1 = (x * b - y * agh ) / agh;
257
- T l2 = (y * a - x * bgh ) / bgh;
260
+ T l1 = (( x * b - y * a) - y * gh ) / agh;
261
+ T l2 = (( y * a - x * b) - x * gh ) / bgh;
258
262
if ((BOOST_MATH_GPU_SAFE_MIN (fabs (l1), fabs (l2)) < 0.2 ))
259
263
{
260
264
// when the base of the exponent is very near 1 we get really
@@ -809,9 +813,8 @@ struct ibeta_fraction2_t
809
813
810
814
BOOST_MATH_GPU_ENABLED result_type operator ()()
811
815
{
812
- T aN = (a + m - 1 ) * (a + b + m - 1 ) * m * (b - m) * x * x;
813
816
T denom = (a + 2 * m - 1 );
814
- aN /= denom * denom;
817
+ T aN = (m * (a + m - 1 ) / denom) * ((a + b + m - 1 ) / denom) * (b - m) * x * x ;
815
818
816
819
T bN = static_cast <T>(m);
817
820
bN += (m * (b - m) * x) / (a + 2 *m - 1 );
@@ -844,7 +847,9 @@ BOOST_MATH_GPU_ENABLED inline T ibeta_fraction2(T a, T b, T x, T y, const Policy
844
847
return result;
845
848
846
849
ibeta_fraction2_t <T> f (a, b, x, y);
847
- T fract = boost::math::tools::continued_fraction_b (f, boost::math::policies::get_epsilon<T, Policy>());
850
+ boost::uintmax_t max_terms = boost::math::policies::get_max_series_iterations<Policy>();
851
+ T fract = boost::math::tools::continued_fraction_b (f, boost::math::policies::get_epsilon<T, Policy>(), max_terms);
852
+ boost::math::policies::check_series_iterations<T>(" boost::math::ibeta" , max_terms, pol);
848
853
BOOST_MATH_INSTRUMENT_VARIABLE (fract);
849
854
BOOST_MATH_INSTRUMENT_VARIABLE (result);
850
855
return result / fract;
@@ -1118,6 +1123,60 @@ BOOST_MATH_GPU_ENABLED T binomial_ccdf(T n, T k, T x, T y, const Policy& pol)
1118
1123
return result;
1119
1124
}
1120
1125
1126
+ template <class T , class Policy >
1127
+ T ibeta_large_ab (T a, T b, T x, T y, bool invert, bool normalised, const Policy& pol)
1128
+ {
1129
+ //
1130
+ // Large arguments, symetric case, see https://dlmf.nist.gov/8.18
1131
+ //
1132
+ BOOST_MATH_STD_USING
1133
+
1134
+ T x0 = a / (a + b);
1135
+ T y0 = b / (a + b);
1136
+ T nu = x0 * log (x / x0) + y0 * log (y / y0 );
1137
+ //
1138
+ // Above compution is unstable, force nu to zero if
1139
+ // something went wrong:
1140
+ //
1141
+ if ((nu > 0 ) || (x == x0) || (y == y0 ))
1142
+ nu = 0 ;
1143
+ nu = sqrt (-2 * nu);
1144
+ //
1145
+ // As per https://dlmf.nist.gov/8.18#E10 we need to make sure we have the correct root:
1146
+ //
1147
+ if ((nu != 0 ) && (nu / (x - x0) < 0 ))
1148
+ nu = -nu;
1149
+ //
1150
+ // The correction term in https://dlmf.nist.gov/8.18#E9 is badly unstable, and often
1151
+ // makes the compution worse not better, we exclude it for now:
1152
+ /*
1153
+ T c0 = 0;
1154
+
1155
+ if (nu != 0)
1156
+ {
1157
+ c0 = 1 / nu;
1158
+ T lim = fabs(10 * tools::epsilon<T>() * c0);
1159
+ c0 -= sqrt(x0 * y0) / (x - x0);
1160
+ if(fabs(c0) < lim)
1161
+ c0 = (1 - 2 * x0) / (3 * sqrt(x0 * y0));
1162
+ else
1163
+ c0 *= exp(a * log(x / x0) + b * log(y / y0));
1164
+ c0 /= sqrt(constants::two_pi<T>() * (a + b));
1165
+ }
1166
+ else
1167
+ {
1168
+ c0 = (1 - 2 * x0) / (3 * sqrt(x0 * y0));
1169
+ c0 /= sqrt(constants::two_pi<T>() * (a + b));
1170
+ }
1171
+ */
1172
+ T mul = 1 ;
1173
+ if (!normalised)
1174
+ mul = beta (a, b, pol);
1175
+
1176
+ return mul * ((invert ? (1 + boost::math::erf (-nu * sqrt ((a + b) / 2 ), pol)) / 2 : boost::math::erfc (-nu * sqrt ((a + b) / 2 ), pol) / 2 ));
1177
+ }
1178
+
1179
+
1121
1180
1122
1181
//
1123
1182
// The incomplete beta function implementation:
@@ -1502,7 +1561,37 @@ BOOST_MATH_GPU_ENABLED T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, b
1502
1561
}
1503
1562
else
1504
1563
{
1505
- fract = ibeta_fraction2 (a, b, x, y, pol, normalised, p_derivative);
1564
+ // a and b both large:
1565
+ bool use_asym = false ;
1566
+ T ma = (std::max)(a, b);
1567
+ T xa = ma == a ? x : y;
1568
+ T saddle = ma / (a + b);
1569
+ T powers = 0 ;
1570
+ if ((ma > 1e-5f / tools::epsilon<T>()) && (ma / (std::min)(a, b) < (xa < saddle ? 2 : 15 )))
1571
+ {
1572
+ if (a == b)
1573
+ use_asym = true ;
1574
+ else
1575
+ {
1576
+ powers = exp (log (x / (a / (a + b))) * a + log (y / (b / (a + b))) * b);
1577
+ if (powers < tools::epsilon<T>())
1578
+ use_asym = true ;
1579
+ }
1580
+ }
1581
+ if (use_asym)
1582
+ {
1583
+ fract = ibeta_large_ab (a, b, x, y, invert, normalised, pol);
1584
+ if (fract * tools::epsilon<T>() < powers)
1585
+ {
1586
+ // Erf approximation failed, correction term is too large, fall back:
1587
+ fract = ibeta_fraction2 (a, b, x, y, pol, normalised, p_derivative);
1588
+ }
1589
+ else
1590
+ invert = false ;
1591
+ }
1592
+ else
1593
+ fract = ibeta_fraction2 (a, b, x, y, pol, normalised, p_derivative);
1594
+
1506
1595
BOOST_MATH_INSTRUMENT_VARIABLE (fract);
1507
1596
}
1508
1597
}
0 commit comments