2
0
mirror of https://github.com/boostorg/math.git synced 2026-01-19 04:22:09 +00:00

More fixes from Rocco Romeo: do the correct thing near a small negative integer, and handle denormalized inputs correctly.

This commit is contained in:
jzmaddock
2014-02-15 19:19:44 +00:00
parent 942288b128
commit 7a823466ca
3 changed files with 67 additions and 7 deletions

View File

@@ -164,7 +164,9 @@ T gamma_imp(T z, const Policy& pol, const Lanczos& l)
}
else if (z < tools::root_epsilon<T>())
{
return 1 / z - constants::euler<T>();
if (z < 1 / tools::max_value<T>())
result = policies::raise_overflow_error<T>(function, 0, pol);
result *= 1 / z - constants::euler<T>();
}
else
{
@@ -242,7 +244,10 @@ 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);
result = log(fabs(1 / z - constants::euler<T>()));
if (fabs(z) < 1 / tools::max_value<T>())
result = -log(z);
else
result = log(fabs(1 / z - constants::euler<T>()));
if (z < 0)
sresult = -1;
}

View File

@@ -308,12 +308,12 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_MATH_CONTROL_FP;
#ifndef BOOST_MATH_BUGGY_LARGE_FLOAT_CONSTANTS
test_spots(0.0F);
test_spots(0.0F, "float");
#endif
test_spots(0.0);
test_spots(0.0, "double");
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
test_spots(0.0L);
test_spots(boost::math::concepts::real_concept(0.1));
test_spots(0.0L, "long double");
test_spots(boost::math::concepts::real_concept(0.1), "real_concept");
#endif
#ifndef BOOST_MATH_BUGGY_LARGE_FLOAT_CONSTANTS

View File

@@ -165,13 +165,20 @@ void test_gamma(T, const char* name)
}
template <class T>
void test_spots(T)
void test_spots(T, const char* name)
{
BOOST_MATH_STD_USING
std::cout << "Testing type " << name << std::endl;
//
// basic sanity checks, tolerance is 50 epsilon expressed as a percentage:
//
T tolerance = boost::math::tools::epsilon<T>() * 5000;
//
// Extra tolerance for real_concept checks which use less accurate code:
//
T extra_tol = boost::is_floating_point<T>::value ? 1 : 20;
BOOST_CHECK_CLOSE(::boost::math::tgamma(static_cast<T>(3.5)), static_cast<T>(3.3233509704478425511840640312646472177454052302295L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(static_cast<T>(0.125)), static_cast<T>(7.5339415987976119046992298412151336246104195881491L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(static_cast<T>(-0.125)), static_cast<T>(-8.7172188593831756100190140408231437691829605421405L), tolerance);
@@ -202,6 +209,24 @@ void test_spots(T)
BOOST_CHECK_CLOSE(::boost::math::tgamma(-ldexp(static_cast<T>(1), -66)), static_cast<T>(-7.37869762948382064645772156649015328606199162983179574406439e19L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-ldexp(static_cast<T>(1), -33)), static_cast<T>(-8.58993459257721566501667413261977598620193488449233402857632e9L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 / boost::math::tools::max_value<T>()), -boost::math::tools::max_value<T>() / 4, tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-1 + ldexp(static_cast<T>(1), -22)), static_cast<T>(-4.19430442278467170746130758391572421252211886167956799318843e6L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-1 - ldexp(static_cast<T>(1), -22)), static_cast<T>(4.19430357721600151046968956086404748206205391186399889108944e6L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 + ldexp(static_cast<T>(1), -20)), static_cast<T>(43690.7294216755534842491085530510391932288379640970386378756L), tolerance * extra_tol);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 - ldexp(static_cast<T>(1), -20)), static_cast<T>(-43690.6039118698506165317137699180871126338425941292693705533L), tolerance * extra_tol);
if (boost::math::tools::digits<T>() > 50)
{
BOOST_CHECK_CLOSE(::boost::math::tgamma(-1 + ldexp(static_cast<T>(1), -44)), static_cast<T>(-1.75921860444164227843350985473932247549232492467032584051825e13L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-1 - ldexp(static_cast<T>(1), -44)), static_cast<T>(1.75921860444155772156649016131144377791001546933519242218430e13L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 + ldexp(static_cast<T>(1), -44)), static_cast<T>(7.33007751850729421569517998006564998020333048893618664936994e11L), tolerance * extra_tol);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 - ldexp(static_cast<T>(1), -44)), static_cast<T>(-7.33007751850603911763815347967171096249288790373790093559568e11L), tolerance * extra_tol);
}
if (boost::math::tools::digits<T>() > 60)
{
BOOST_CHECK_CLOSE(::boost::math::tgamma(-1 + ldexp(static_cast<T>(1), -55)), static_cast<T>(-3.60287970189639684227843350984671785799289582631555600561524e16L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-1 - ldexp(static_cast<T>(1), -55)), static_cast<T>(3.60287970189639675772156649015328997929531384279596450489170e16L), tolerance);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 + ldexp(static_cast<T>(1), -55)), static_cast<T>(1.50119987579016539608823618465835611632004877549994080474627e15L), tolerance * extra_tol);
BOOST_CHECK_CLOSE(::boost::math::tgamma(-4 - ldexp(static_cast<T>(1), -55)), static_cast<T>(-1.50119987579016527057843048200831672241827850458884790004313e15L), tolerance * extra_tol);
}
#ifdef BOOST_MSVC
#pragma warning(push)
@@ -274,5 +299,35 @@ void test_spots(T)
BOOST_CHECK(sign == -1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 / boost::math::tools::max_value<T>(), &sign), log(boost::math::tools::max_value<T>() / 4), tolerance);
BOOST_CHECK(sign == -1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-1 + ldexp(static_cast<T>(1), -22), &sign), log(static_cast<T>(4.19430442278467170746130758391572421252211886167956799318843e6L)), tolerance);
BOOST_CHECK(sign == -1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-1 - ldexp(static_cast<T>(1), -22), &sign), log(static_cast<T>(4.19430357721600151046968956086404748206205391186399889108944e6L)), tolerance);
BOOST_CHECK(sign == 1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 + ldexp(static_cast<T>(1), -20), &sign), log(static_cast<T>(43690.7294216755534842491085530510391932288379640970386378756L)), tolerance * extra_tol);
BOOST_CHECK(sign == 1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 - ldexp(static_cast<T>(1), -20), &sign), log(static_cast<T>(43690.6039118698506165317137699180871126338425941292693705533L)), tolerance * extra_tol);
BOOST_CHECK(sign == -1);
if (boost::math::tools::digits<T>() > 50)
{
BOOST_CHECK_CLOSE(::boost::math::lgamma(-1 + ldexp(static_cast<T>(1), -44), &sign), log(static_cast<T>(1.75921860444164227843350985473932247549232492467032584051825e13L)), tolerance);
BOOST_CHECK(sign == -1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-1 - ldexp(static_cast<T>(1), -44), &sign), log(static_cast<T>(1.75921860444155772156649016131144377791001546933519242218430e13L)), tolerance);
BOOST_CHECK(sign == 1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 + ldexp(static_cast<T>(1), -44), &sign), log(static_cast<T>(7.33007751850729421569517998006564998020333048893618664936994e11L)), tolerance * extra_tol);
BOOST_CHECK(sign == 1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 - ldexp(static_cast<T>(1), -44), &sign), log(static_cast<T>(7.33007751850603911763815347967171096249288790373790093559568e11L)), tolerance * extra_tol);
BOOST_CHECK(sign == -1);
}
if (boost::math::tools::digits<T>() > 60)
{
BOOST_CHECK_CLOSE(::boost::math::lgamma(-1 + ldexp(static_cast<T>(1), -55), &sign), log(static_cast<T>(3.60287970189639684227843350984671785799289582631555600561524e16L)), tolerance);
BOOST_CHECK(sign == -1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-1 - ldexp(static_cast<T>(1), -55), &sign), log(static_cast<T>(3.60287970189639675772156649015328997929531384279596450489170e16L)), tolerance);
BOOST_CHECK(sign == 1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 + ldexp(static_cast<T>(1), -55), &sign), log(static_cast<T>(1.50119987579016539608823618465835611632004877549994080474627e15L)), tolerance * extra_tol);
BOOST_CHECK(sign == 1);
BOOST_CHECK_CLOSE(::boost::math::lgamma(-4 - ldexp(static_cast<T>(1), -55), &sign), log(static_cast<T>(1.50119987579016527057843048200831672241827850458884790004313e15L)), tolerance * extra_tol);
BOOST_CHECK(sign == -1);
}
}