Skip to content

Commit

Permalink
Merge pull request #884 from boostorg/ibeta_small_args
Browse files Browse the repository at this point in the history
More and better handling of ibeta small args.
  • Loading branch information
jzmaddock authored Nov 28, 2022
2 parents 0dc6a70 + 20fc2ad commit ea8d3bf
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
3 changes: 3 additions & 0 deletions include/boost/math/special_functions/beta.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,9 @@ T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_deriva
T cgh = static_cast<T>(c + Lanczos::g() - 0.5f);
result = Lanczos::lanczos_sum_expG_scaled(c) / (Lanczos::lanczos_sum_expG_scaled(a) * Lanczos::lanczos_sum_expG_scaled(b));

if (!(boost::math::isfinite)(result))
result = 0;

T l1 = log(cgh / bgh) * (b - 0.5f);
T l2 = log(x * cgh / agh) * a;
//
Expand Down
40 changes: 37 additions & 3 deletions include/boost/math/special_functions/detail/ibeta_inverse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,12 @@ T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
#endif
{
bet = boost::math::beta(a, b, pol);

typedef typename Policy::overflow_error_type overflow_type;

BOOST_IF_CONSTEXPR(overflow_type::value != boost::math::policies::throw_on_error)
if(bet > tools::max_value<T>())
bet = tools::max_value<T>();
}
#ifndef BOOST_NO_EXCEPTIONS
catch (const std::overflow_error&)
Expand Down Expand Up @@ -686,7 +692,7 @@ T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
invert = !invert;
xs = 1 - xs;
}
if (a < tools::min_value<T>())
if ((a < tools::min_value<T>()) && (b > tools::min_value<T>()))
{
if (py)
{
Expand Down Expand Up @@ -715,6 +721,8 @@ T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
if (overflow || !(boost::math::isfinite)(bet))
{
xg = exp((boost::math::lgamma(a + 1, pol) + boost::math::lgamma(b, pol) - boost::math::lgamma(a + b, pol) + log(p)) / a);
if (xg > 2 / tools::epsilon<T>())
xg = 2 / tools::epsilon<T>();
}
else
xg = pow(a * p * bet, 1/a);
Expand Down Expand Up @@ -814,15 +822,41 @@ T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
}
if(pow(p, 1/a) < 0.5)
{
x = pow(p * a * boost::math::beta(a, b, pol), 1 / a);
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
x = pow(p * a * boost::math::beta(a, b, pol), 1 / a);
if ((x > 1) || !(boost::math::isfinite)(x))
x = 1;
#ifndef BOOST_NO_EXCEPTIONS
}
catch (const std::overflow_error&)
{
x = 1;
}
#endif
if(x == 0)
x = boost::math::tools::min_value<T>();
y = 1 - x;
}
else /*if(pow(q, 1/b) < 0.1)*/
{
// model a distorted quarter circle:
y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b);
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b);
if ((y > 1) || !(boost::math::isfinite)(y))
y = 1;
#ifndef BOOST_NO_EXCEPTIONS
}
catch (const std::overflow_error&)
{
y = 1;
}
#endif
if(y == 0)
y = boost::math::tools::min_value<T>();
x = 1 - y;
Expand Down
2 changes: 1 addition & 1 deletion include/boost/math/special_functions/gamma.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
//
// TODO: is this still required? Lanczos approx should be better now?
//
if(z <= tools::log_min_value<T>())
if((z <= tools::log_min_value<T>()) || (a < 1 / tools::max_value<T>()))
{
// Oh dear, have to use logs, should be free of cancellation errors though:
return exp(a * log(z) - z - lgamma_imp(a, pol, l));
Expand Down
11 changes: 11 additions & 0 deletions test/test_ibeta_inv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,5 +305,16 @@ void test_spots(T)
BOOST_MATH_CHECK_THROW(::boost::math::ibeta_inv(static_cast<T>(2.125), -n, static_cast<T>(0.125)), std::domain_error);
BOOST_MATH_CHECK_THROW(::boost::math::ibeta_inv(static_cast<T>(2.125), static_cast<T>(1.125), -n), std::domain_error);
}
if (std::numeric_limits<T>::has_denorm)
{
T m = std::numeric_limits<T>::denorm_min();
T small = 2 * (std::numeric_limits<T>::min)();
BOOST_CHECK((boost::math::isfinite)(boost::math::ibeta_inv(m, static_cast<T>(2.125), static_cast<T>(0.125))));
BOOST_CHECK((boost::math::isfinite)(boost::math::ibeta_inv(m, m, static_cast<T>(0.125))));
BOOST_CHECK_LT(boost::math::ibeta_inv(m, static_cast<T>(12.125), static_cast<T>(0.125)), small);
BOOST_CHECK((boost::math::isfinite)(boost::math::ibeta_inv(static_cast<T>(2.125), m, static_cast<T>(0.125))));
BOOST_CHECK((boost::math::isfinite)(boost::math::ibeta_inv(static_cast<T>(12.125), m, static_cast<T>(0.125))));
BOOST_CHECK((boost::math::isfinite)(boost::math::ibeta_inv(m, m, static_cast<T>(0.125))));
}
}

0 comments on commit ea8d3bf

Please sign in to comment.