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

Improve error handling in non-central distributions. (#963)

* Improve error handling in non-central distributions.

* Try turning debug symbols off for msvc-14.0.
So we don't run out of disk space on CI.
This commit is contained in:
jzmaddock
2023-03-07 12:11:29 +00:00
committed by GitHub
parent bf3bc2e6c2
commit cf6cd75477
10 changed files with 126 additions and 57 deletions

View File

@@ -214,7 +214,7 @@ jobs:
run: config_info_travis
working-directory: ../boost-root/libs/config/test
- name: Test
run: ..\..\..\b2 --hash %ARGS% define=CI_SUPPRESS_KNOWN_ISSUES ${{ matrix.suite }}
run: ..\..\..\b2 --hash %ARGS% define=CI_SUPPRESS_KNOWN_ISSUES debug-symbols=off ${{ matrix.suite }}
working-directory: ../boost-root/libs/math/test
windows_gcc:
runs-on: windows-2019

View File

@@ -185,11 +185,12 @@ inline bool check_non_centrality(
RealType* result,
const Policy& pol)
{
if((ncp < 0) || !(boost::math::isfinite)(ncp))
{ // Assume scale == 0 is NOT valid for any distribution.
static const RealType upper_limit = static_cast<RealType>((std::numeric_limits<long long>::max)()) - boost::math::policies::get_max_root_iterations<Policy>();
if((ncp < 0) || !(boost::math::isfinite)(ncp) || ncp > upper_limit)
{
*result = policies::raise_domain_error<RealType>(
function,
"Non centrality parameter is %1%, but must be > 0 !", ncp, pol);
"Non centrality parameter is %1%, but must be > 0, and a countable value such that x+1 != x", ncp, pol);
return false;
}
return true;

View File

@@ -430,7 +430,7 @@ namespace boost
static_cast<value_type>(p),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
//
// Special cases first:
//
@@ -624,7 +624,7 @@ namespace boost
static_cast<value_type>(x),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(l == 0)
return pdf(boost::math::beta_distribution<RealType, Policy>(dist.alpha(), dist.beta()), x);
@@ -761,7 +761,7 @@ namespace boost
l,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
RealType c = a + b + l / 2;
RealType mean = 1 - (b / c) * (1 + l / (2 * c * c));
return detail::generic_find_mode_01(
@@ -872,7 +872,7 @@ namespace boost
x,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(l == 0)
return cdf(beta_distribution<RealType, Policy>(a, b), x);
@@ -909,7 +909,7 @@ namespace boost
x,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(l == 0)
return cdf(complement(beta_distribution<RealType, Policy>(a, b), x));

View File

@@ -88,7 +88,7 @@ namespace boost
// stable direction for the gamma function
// recurrences:
//
int i;
long long i;
for(i = k; static_cast<std::uintmax_t>(i-k) < max_iter; ++i)
{
T term = poisf * gamf;
@@ -299,7 +299,7 @@ namespace boost
if(pois == 0)
return 0;
T poisb = pois;
for(int i = k; ; ++i)
for(long long i = k; ; ++i)
{
sum += pois;
if(pois / sum < errtol)
@@ -310,7 +310,7 @@ namespace boost
"Series did not converge, closest value was %1%", sum, pol);
pois *= l2 * x2 / ((i + 1) * (n2 + i));
}
for(int i = k - 1; i >= 0; --i)
for(long long i = k - 1; i >= 0; --i)
{
poisb *= (i + 1) * (n2 + i) / (l2 * x2);
sum += poisb;
@@ -428,7 +428,7 @@ namespace boost
static_cast<value_type>(p),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
//
// Special cases get short-circuited first:
//
@@ -519,7 +519,7 @@ namespace boost
(value_type)x,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(l == 0)
return pdf(boost::math::chi_squared_distribution<RealType, forwarding_policy>(dist.degrees_of_freedom()), x);
@@ -821,7 +821,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return static_cast<RealType>(r);
return k + l;
} // mean
@@ -842,7 +842,7 @@ namespace boost
l,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
bool asymptotic_mode = k < l/4;
RealType starting_point = asymptotic_mode ? k + l - RealType(3) : RealType(1) + k;
return detail::generic_find_mode(dist, starting_point, function);
@@ -864,7 +864,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return static_cast<RealType>(r);
return 2 * (2 * l + k);
}
@@ -887,7 +887,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return static_cast<RealType>(r);
BOOST_MATH_STD_USING
return pow(2 / (k + 2 * l), RealType(3)/2) * (k + 3 * l);
}
@@ -908,7 +908,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return static_cast<RealType>(r);
return 12 * (k + 4 * l) / ((k + 2 * l) * (k + 2 * l));
} // kurtosis_excess
@@ -946,7 +946,7 @@ namespace boost
x,
&r,
Policy()))
return r;
return static_cast<RealType>(r);
return detail::non_central_chi_squared_cdf(x, k, l, false, Policy());
} // cdf
@@ -975,7 +975,7 @@ namespace boost
x,
&r,
Policy()))
return r;
return static_cast<RealType>(r);
return detail::non_central_chi_squared_cdf(x, k, l, true, Policy());
} // ccdf

View File

@@ -106,7 +106,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return r;
if(v2 <= 2)
return policies::raise_domain_error(
function,
@@ -137,7 +137,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return r;
RealType guess = m > 2 ? RealType(m * (n + l) / (n * (m - 2))) : RealType(1);
return detail::generic_find_mode(
dist,
@@ -166,7 +166,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return r;
if(m <= 4)
return policies::raise_domain_error(
function,
@@ -203,7 +203,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return r;
if(m <= 6)
return policies::raise_domain_error(
function,
@@ -240,7 +240,7 @@ namespace boost
l,
&r,
Policy()))
return r;
return r;
if(m <= 8)
return policies::raise_domain_error(
function,
@@ -309,7 +309,7 @@ namespace boost
dist.non_centrality(),
&r,
Policy()))
return r;
return r;
if((x < 0) || !(boost::math::isfinite)(x))
{
@@ -350,7 +350,7 @@ namespace boost
c.dist.non_centrality(),
&r,
Policy()))
return r;
return r;
if((c.param < 0) || !(boost::math::isfinite)(c.param))
{

View File

@@ -307,9 +307,9 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
delta,
static_cast<T>(delta * delta),
&r,
Policy())
||
@@ -730,9 +730,9 @@ namespace boost
detail::check_df_gt0_to_inf(
function,
v, &r, Policy());
detail::check_finite(
detail::check_non_centrality(
function,
lambda,
static_cast<value_type>(lambda * lambda),
&r,
Policy());
} // non_central_t_distribution constructor.
@@ -874,12 +874,12 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
BOOST_MATH_STD_USING
@@ -912,12 +912,12 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(v <= 1)
return policies::raise_domain_error<RealType>(
function,
@@ -947,12 +947,12 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(v <= 2)
return policies::raise_domain_error<RealType>(
function,
@@ -982,12 +982,12 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(v <= 3)
return policies::raise_domain_error<RealType>(
function,
@@ -1014,12 +1014,12 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if(v <= 4)
return policies::raise_domain_error<RealType>(
function,
@@ -1053,9 +1053,9 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l), // we need l^2 to be countable.
&r,
Policy())
||
@@ -1064,7 +1064,7 @@ namespace boost
t,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
detail::non_central_t_pdf(static_cast<value_type>(v),
static_cast<value_type>(l),
@@ -1093,9 +1093,9 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy())
||
@@ -1104,8 +1104,8 @@ namespace boost
x,
&r,
Policy()))
return (RealType)r;
if ((boost::math::isinf)(v))
return static_cast<RealType>(r);
if ((boost::math::isinf)(v))
{ // Infinite degrees of freedom, so use normal distribution located at delta.
normal_distribution<RealType, Policy> n(l, 1);
cdf(n, x);
@@ -1147,9 +1147,9 @@ namespace boost
function,
v, &r, Policy())
||
!detail::check_finite(
!detail::check_non_centrality(
function,
l,
static_cast<RealType>(l * l),
&r,
Policy())
||
@@ -1158,7 +1158,7 @@ namespace boost
x,
&r,
Policy()))
return (RealType)r;
return static_cast<RealType>(r);
if ((boost::math::isinf)(v))
{ // Infinite degrees of freedom, so use normal distribution located at delta.

View File

@@ -257,6 +257,22 @@ void test_spots(RealType)
BOOST_MATH_CHECK_THROW(skewness(dist), boost::math::evaluation_error);
BOOST_MATH_CHECK_THROW(kurtosis(dist), boost::math::evaluation_error);
BOOST_MATH_CHECK_THROW(kurtosis_excess(dist), boost::math::evaluation_error);
//
// Some special error handling tests, if the non-centrality param is too large
// then we have no evaluation method and should get a domain_error:
//
using std::ldexp;
using distro1 = boost::math::non_central_beta_distribution<RealType>;
using distro2 = boost::math::non_central_beta_distribution<RealType, boost::math::policies::policy<boost::math::policies::domain_error<boost::math::policies::ignore_error>>>;
using de = std::domain_error;
BOOST_MATH_CHECK_THROW(distro1(2, 3, ldexp(RealType(1), 100)), de);
if (std::numeric_limits<RealType>::has_quiet_NaN)
{
distro2 d2(2, 3, ldexp(RealType(1), 100));
BOOST_CHECK(boost::math::isnan(pdf(d2, 0.5)));
BOOST_CHECK(boost::math::isnan(cdf(d2, 0.5)));
BOOST_CHECK(boost::math::isnan(cdf(complement(d2, 0.5))));
}
} // template <class RealType>void test_spots(RealType)

View File

@@ -3,7 +3,10 @@
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_OVERFLOW_ERROR_POLICY
#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
#endif
#include <boost/math/concepts/real_concept.hpp>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
@@ -271,6 +274,22 @@ void test_spots(RealType)
BOOST_MATH_CHECK_THROW(pdf(boost::math::non_central_chi_squared_distribution<RealType>(1, -1), 0), std::domain_error);
BOOST_MATH_CHECK_THROW(quantile(boost::math::non_central_chi_squared_distribution<RealType>(1, 1), -1), std::domain_error);
BOOST_MATH_CHECK_THROW(quantile(boost::math::non_central_chi_squared_distribution<RealType>(1, 1), 2), std::domain_error);
//
// Some special error handling tests, if the non-centrality param is too large
// then we have no evaluation method and should get a domain_error:
//
using std::ldexp;
using distro1 = boost::math::non_central_chi_squared_distribution<RealType>;
using distro2 = boost::math::non_central_chi_squared_distribution<RealType, boost::math::policies::policy<boost::math::policies::domain_error<boost::math::policies::ignore_error>>>;
using de = std::domain_error;
BOOST_MATH_CHECK_THROW(distro1(2, ldexp(RealType(1), 100)), de);
if (std::numeric_limits<RealType>::has_quiet_NaN)
{
distro2 d2(2, ldexp(RealType(1), 100));
BOOST_CHECK(boost::math::isnan(pdf(d2, 0.5)));
BOOST_CHECK(boost::math::isnan(cdf(d2, 0.5)));
BOOST_CHECK(boost::math::isnan(cdf(complement(d2, 0.5))));
}
#endif
} // template <class RealType>void test_spots(RealType)

View File

@@ -293,6 +293,21 @@ void test_spots(RealType)
BOOST_MATH_CHECK_THROW(pdf(boost::math::non_central_f_distribution<RealType>(1, -1, 1), 0), std::domain_error);
BOOST_MATH_CHECK_THROW(quantile(boost::math::non_central_f_distribution<RealType>(1, 1, 1), -1), std::domain_error);
BOOST_MATH_CHECK_THROW(quantile(boost::math::non_central_f_distribution<RealType>(1, 1, 1), 2), std::domain_error);
//
// Some special error handling tests, if the non-centrality param is too large
// then we have no evaluation method and should get a domain_error:
//
using std::ldexp;
using distro1 = boost::math::non_central_f_distribution<RealType>;
using distro2 = boost::math::non_central_f_distribution<RealType, boost::math::policies::policy<boost::math::policies::domain_error<boost::math::policies::ignore_error>>>;
using de = std::domain_error;
BOOST_MATH_CHECK_THROW(distro1(2, 3, ldexp(RealType(1), 100)), de);
if (std::numeric_limits<RealType>::has_quiet_NaN)
{
distro2 d2(2, 3, ldexp(RealType(1), 100));
BOOST_CHECK(boost::math::isnan(pdf(d2, 0.5)));
BOOST_CHECK(boost::math::isnan(cdf(d2, 0.5)));
}
} // template <class RealType>void test_spots(RealType)
BOOST_AUTO_TEST_CASE( test_main )

View File

@@ -3,7 +3,10 @@
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_OVERFLOW_ERROR_POLICY
#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
#endif
#include <boost/math/concepts/real_concept.hpp>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
@@ -302,6 +305,21 @@ void test_spots(RealType)
BOOST_MATH_CHECK_THROW(pdf(boost::math::non_central_t_distribution<RealType>(-1, 1), 0), std::domain_error);
BOOST_MATH_CHECK_THROW(quantile(boost::math::non_central_t_distribution<RealType>(1, 1), -1), std::domain_error);
BOOST_MATH_CHECK_THROW(quantile(boost::math::non_central_t_distribution<RealType>(1, 1), 2), std::domain_error);
//
// Some special error handling tests, if the non-centrality param is too large
// then we have no evaluation method and should get a domain_error:
//
using std::ldexp;
using distro1 = boost::math::non_central_t_distribution<RealType>;
using distro2 = boost::math::non_central_t_distribution<RealType, boost::math::policies::policy<boost::math::policies::domain_error<boost::math::policies::ignore_error>>>;
using de = std::domain_error;
BOOST_MATH_CHECK_THROW(distro1(2, ldexp(RealType(1), 100)), de);
if (std::numeric_limits<RealType>::has_quiet_NaN)
{
distro2 d2(2, ldexp(RealType(1), 100));
BOOST_CHECK(boost::math::isnan(pdf(d2, 0.5)));
BOOST_CHECK(boost::math::isnan(cdf(d2, 0.5)));
}
} // template <class RealType>void test_spots(RealType)
template <class T>