Skip to content

Commit

Permalink
Merge pull request boostorg#408 from boostorg/issue406
Browse files Browse the repository at this point in the history
Fix bug in student's T quantile for denormalized degrees_of_freedom.
  • Loading branch information
jzmaddock authored Jul 27, 2020
2 parents 326faa4 + a316c72 commit c4972b0
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 2 deletions.
29 changes: 28 additions & 1 deletion include/boost/math/special_functions/detail/ibeta_inverse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,34 @@ T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
invert = !invert;
xs = 1 - xs;
}
T xg = pow(a * p * boost::math::beta(a, b, pol), 1/a);
if (a < tools::min_value<T>())
{
if (py)
{
*py = invert ? 0 : 1;
}
return invert ? 1 : 0; // nothing interesting going on here.
}
//
// The call to beta may overflow, plus the alternative using lgamma may do the same
// if T is a type where 1/T is infinite for small values (denorms for example).
//
T bet = 0;
T xg;
bool overflow = false;
try {
bet = boost::math::beta(a, b, pol);
}
catch (const std::runtime_error&)
{
overflow = true;
}
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);
}
else
xg = pow(a * p * bet, 1/a);
x = xg / (1 + xg);
y = 1 / (1 + xg);
//
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 @@ -240,7 +240,7 @@ T lgamma_imp(T z, const Policy& pol, const Lanczos& l, int* sign = 0)
{
if (0 == z)
return policies::raise_pole_error<T>(function, "Evaluation of lgamma at %1%.", z, pol);
if (fabs(z) < 1 / tools::max_value<T>())
if (4 * fabs(z) < tools::epsilon<T>())
result = -log(fabs(z));
else
result = log(fabs(1 / z - constants::euler<T>()));
Expand Down
12 changes: 12 additions & 0 deletions test/test_gamma.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,5 +333,17 @@ void test_spots(T, const char* name)
BOOST_CHECK_CLOSE(::boost::math::lgamma(ldexp(static_cast<T>(11103367432951928LL), 62)), static_cast<T>(4.0411767712186990905102512019058204792570873633363159e36L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::lgamma(ldexp(static_cast<T>(11103367432951928LL), 326)), static_cast<T>(3.9754720509185529233002820161357111676582583112671658e116L), tolerance);
}
//
// Super small values may cause spurious overflow:
//
if (std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_denorm)
{
T value = (std::numeric_limits<T>::min)();
while (value != 0)
{
BOOST_CHECK((boost::math::isfinite)(boost::math::lgamma(value)));
value /= 2;
}
}
}

7 changes: 7 additions & 0 deletions test/test_students_t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,13 @@ void test_spots(RealType)
boost::math::quantile(
students_t_distribution<RealType>(static_cast<RealType>(0x0fffffff)), static_cast<RealType>(0.25f))),
static_cast<RealType>(0.25f), tolerance);
//
// Bug cases:
//
if (std::numeric_limits<RealType>::is_specialized && std::numeric_limits<RealType>::has_denorm)
{
BOOST_CHECK_THROW(boost::math::quantile(students_t_distribution<RealType>((std::numeric_limits<RealType>::min)() / 2), static_cast<RealType>(0.0025f)), std::overflow_error);
}
}

// Student's t pdf tests.
Expand Down

0 comments on commit c4972b0

Please sign in to comment.