From fbffcf0700392f85c0fe7c2feb392f90a181e630 Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Mon, 25 May 2026 16:24:42 -0700 Subject: [PATCH 1/7] Completed test coverage for arcsine distribution --- test/test_arcsine.cpp | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/test/test_arcsine.cpp b/test/test_arcsine.cpp index cb5646e627..dc2fba919e 100644 --- a/test/test_arcsine.cpp +++ b/test/test_arcsine.cpp @@ -105,6 +105,7 @@ void test_ignore_policy(RealType) //std::cout << "pdf(ignore_error_arcsine(-1, +1), std::numeric_limits::infinity()) = " << pdf(ignore_error_arcsine(-1, +1), std::numeric_limits::infinity()) << std::endl; // Outputs: pdf(ignore_error_arcsine(-1, +1), std::numeric_limits::infinity()) = 1.#QNAN } + // PDF BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_arcsine(0, 1), std::numeric_limits::infinity()))); // x == infinity BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_arcsine(-1, 1), std::numeric_limits::infinity()))); // x == infinity BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_arcsine(0, 1), static_cast (-2)))); // x < xmin @@ -120,9 +121,31 @@ void test_ignore_policy(RealType) BOOST_CHECK((boost::math::isnan)(logpdf(ignore_error_arcsine(0, 1), static_cast (+2)))); // x > x_max BOOST_CHECK((boost::math::isnan)(logpdf(ignore_error_arcsine(-1, 1), static_cast (+2)))); // x > x_max + // CDF + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_arcsine(0, 1), std::numeric_limits::infinity()))); // x == infinity + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_arcsine(-1, 1), std::numeric_limits::infinity()))); // x == infinity + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_arcsine(0, 1), static_cast (-2)))); // x < xmin + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_arcsine(-1, 1), static_cast (-2)))); // x < xmin + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_arcsine(0, 1), static_cast (+2)))); // x > x_max + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_arcsine(-1, 1), static_cast (+2)))); // x > x_max + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_arcsine(0, 1), std::numeric_limits::infinity())))); // x == infinity + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_arcsine(0, 1), static_cast (-2))))); // x < xmin + + // Quantile + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_arcsine(0, 1), std::numeric_limits::infinity()))); // p == infinity + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_arcsine(0, 1), static_cast(-1)))); // p < 0 + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_arcsine(0, 1), static_cast(2)))); // p > 1 + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_arcsine(0, 1), std::numeric_limits::infinity())))); // q == infinity + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_arcsine(0, 1), static_cast(-1))))); // q < 0 + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_arcsine(0, 1), static_cast(2))))); // q > 1 + // Mean BOOST_CHECK((boost::math::isnan)(mean(ignore_error_arcsine(-nan, 0)))); BOOST_CHECK((boost::math::isnan)(mean(ignore_error_arcsine(+nan, 0)))); + + // Median + BOOST_CHECK((boost::math::isnan)(median(ignore_error_arcsine(-nan, 0)))); + BOOST_CHECK((boost::math::isnan)(median(ignore_error_arcsine(+nan, 0)))); if (std::numeric_limits::has_infinity) { @@ -276,7 +299,8 @@ void test_spots(RealType) BOOST_CHECK_EQUAL(variance(arcsine_01), 0.125); // 1/8 = 0.125 BOOST_CHECK_CLOSE_FRACTION(standard_deviation(arcsine_01), one_div_root_two() / 2, tolerance); // 1/ sqrt(s) = 0.35355339059327379 BOOST_CHECK_EQUAL(skewness(arcsine_01), 0); // - BOOST_CHECK_EQUAL(kurtosis_excess(arcsine_01), -1.5); // 3/2 + BOOST_CHECK_EQUAL(kurtosis_excess(arcsine_01), -1.5); // -3/2 + BOOST_CHECK_EQUAL(kurtosis(arcsine_01), 1.5); // 3/2 BOOST_CHECK_EQUAL(support(arcsine_01).first, 0); // BOOST_CHECK_EQUAL(range(arcsine_01).first, 0); // BOOST_CHECK_THROW(mode(arcsine_01), std::domain_error); // Two modes at x_min and x_max, so throw instead. @@ -374,8 +398,8 @@ void test_spots(RealType) BOOST_CHECK_EQUAL(variance(as_m11), 0.5); // 1 - (-1) = 2 ^ 2 = 4 /8 = 0.5 BOOST_CHECK_EQUAL(skewness(as_m11), 0); // - BOOST_CHECK_EQUAL(kurtosis_excess(as_m11), -1.5); // 3/2 - + BOOST_CHECK_EQUAL(kurtosis_excess(as_m11), -1.5); // -3/2 + BOOST_CHECK_EQUAL(kurtosis(as_m11), 1.5); // 3/2 BOOST_CHECK_CLOSE_FRACTION(pdf(as_m11, 0.05), static_cast(0.31870852113797122803869876869296281629727218095644L), tolerance); BOOST_CHECK_CLOSE_FRACTION(pdf(as_m11, 0.5), static_cast(0.36755259694786136634088433220864629426492432024443L), tolerance); @@ -428,7 +452,8 @@ void test_spots(RealType) BOOST_CHECK_EQUAL(median(as_m2m1), -1.5); // 1 / (1 + 1) = 1/2 exactly. BOOST_CHECK_EQUAL(variance(as_m2m1), 0.125); BOOST_CHECK_EQUAL(skewness(as_m2m1), 0); // - BOOST_CHECK_EQUAL(kurtosis_excess(as_m2m1), -1.5); // 3/2 + BOOST_CHECK_EQUAL(kurtosis(as_m2m1), 1.5); // 3/2 + BOOST_CHECK_EQUAL(kurtosis_excess(as_m2m1), -1.5); // -3/2 BOOST_CHECK_CLOSE_FRACTION(pdf(as_m2m1, -1.95), static_cast(1.4605059227421865250256574657088244053723856445614L), 4 * tolerance); BOOST_CHECK_CLOSE_FRACTION(pdf(as_m2m1, -1.5), static_cast(0.63661977236758134307553505349005744813783858296183L), tolerance); @@ -615,7 +640,8 @@ void test_spots(RealType) BOOST_CHECK_EQUAL(variance(as), 0.125); //0.125 BOOST_CHECK_CLOSE_FRACTION(standard_deviation(as), one_div_root_two() / 2, std::numeric_limits::epsilon()); // 0.353553 BOOST_CHECK_EQUAL(skewness(as), 0); // - BOOST_CHECK_EQUAL(kurtosis_excess(as), -1.5); // 3/2 + BOOST_CHECK_EQUAL(kurtosis(as), 1.5); // 3/2 + BOOST_CHECK_EQUAL(kurtosis_excess(as), -1.5); // -3/2 BOOST_CHECK_EQUAL(support(as).first, 0); // BOOST_CHECK_EQUAL(range(as).first, 0); // BOOST_CHECK_THROW(mode(as), std::domain_error); // Two modes at x_min and x_max, so throw instead. From 0d7c2459b9724c6efa129692aef9a6951e0c8459 Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Mon, 25 May 2026 17:53:49 -0700 Subject: [PATCH 2/7] Added bernoulli distribution tests --- test/test_bernoulli.cpp | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/test_bernoulli.cpp b/test/test_bernoulli.cpp index 5f78b0afc5..256a897783 100644 --- a/test/test_bernoulli.cpp +++ b/test/test_bernoulli.cpp @@ -114,6 +114,11 @@ void test_spots(RealType) bernoulli_distribution(static_cast(0.4L)), static_cast(0)), static_cast(0.6L), tolerance); // Expect 1- p. + BOOST_CHECK_CLOSE_FRACTION( + pdf( // OK k (or n) + bernoulli_distribution(static_cast(0.4L)), static_cast(1)), + static_cast(0.4L), tolerance); // Expect p. + BOOST_CHECK_EQUAL( mean(bernoulli_distribution(static_cast(0.5L))), static_cast(0.5L)); @@ -280,6 +285,46 @@ void test_spots(RealType) BOOST_MATH_CHECK_THROW(quantile(complement(w, +inf)), std::domain_error); // p = + inf } // has_infinity #endif + + using boost::math::policies::policy; + typedef policy< + boost::math::policies::domain_error, + boost::math::policies::overflow_error, + boost::math::policies::underflow_error, + boost::math::policies::denorm_error, + boost::math::policies::pole_error, + boost::math::policies::evaluation_error + > ignore_all_policy; + + typedef bernoulli_distribution ignore_error_bernoulli; + + if (std::numeric_limits::has_quiet_NaN) + { + // PDF + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_bernoulli(0.5), std::numeric_limits::infinity()))); // k == infinity + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_bernoulli(0.5), 2))); // k > 1 + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_bernoulli(0.5), static_cast(0.5)))); // k != 0, 1 + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_bernoulli(0.5), static_cast(-0.5)))); // k != 0, 1 + + // CDF + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_bernoulli(0.5), std::numeric_limits::infinity()))); // k == infinity + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_bernoulli(0.5), 2))); // k > 1 + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_bernoulli(0.5), static_cast(0.5)))); // k != 0, 1 + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_bernoulli(0.5), static_cast(-0.5)))); // k != 0, 1 + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_bernoulli(0.5), std::numeric_limits::infinity())))); // k == infinity + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_bernoulli(0.5), 2)))); // k > 1 + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_bernoulli(0.5), static_cast(0.5))))); // k != 0, 1 + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_bernoulli(0.5), static_cast(-0.5))))); // k != 0, 1 + + // // Quantile + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_bernoulli(0.5), std::numeric_limits::infinity()))); // p == infinity + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_bernoulli(0.5), static_cast(-1)))); // p < 0 + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_bernoulli(0.5), static_cast(2)))); // p > 1 + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_bernoulli(0.5), std::numeric_limits::infinity())))); // q == infinity + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_bernoulli(0.5), static_cast(-1))))); // q < 0 + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_bernoulli(0.5), static_cast(2))))); // q > 1 + + } // has_quiet_NaN } // template void test_spots(RealType) BOOST_AUTO_TEST_CASE( test_main ) From 264487e3543d86ee3d877d7691225cb8bcd7e98f Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Mon, 25 May 2026 20:11:23 -0700 Subject: [PATCH 3/7] Added beta distribution --- test/test_beta_dist.cpp | 68 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/test/test_beta_dist.cpp b/test/test_beta_dist.cpp index d989197b6b..3983f526ff 100644 --- a/test/test_beta_dist.cpp +++ b/test/test_beta_dist.cpp @@ -65,6 +65,18 @@ using std::numeric_limits; # include #endif +template +void test_find_alpha_beta(RealType mean, RealType variance){ + BOOST_MATH_CHECK_THROW(beta_distribution::find_alpha(mean, variance), std::domain_error); + BOOST_MATH_CHECK_THROW(beta_distribution::find_beta(mean, variance), std::domain_error); +} + +template +void test_find_alpha_beta(RealType param, RealType x, RealType p){ + BOOST_MATH_CHECK_THROW(beta_distribution::find_alpha(param, x, p), std::domain_error); + BOOST_MATH_CHECK_THROW(beta_distribution::find_beta(param, x, p), std::domain_error); +} + template void test_spot( RealType a, // alpha a @@ -175,7 +187,9 @@ void test_spots(RealType) using ::boost::math::pdf; // Tests that should throw: - BOOST_MATH_CHECK_THROW(mode(beta_distribution(static_cast(1), static_cast(1))), std::domain_error); + BOOST_MATH_CHECK_THROW(mode(beta_distribution(static_cast(1), static_cast(1))), std::domain_error); // alpha = beta = 1 + BOOST_MATH_CHECK_THROW(mode(beta_distribution(static_cast(2), static_cast(1))), std::domain_error); // beta = 1 + BOOST_MATH_CHECK_THROW(mode(beta_distribution(static_cast(1), static_cast(2))), std::domain_error); // alpha = 1 // mode is undefined, and throws domain_error! // BOOST_MATH_CHECK_THROW(median(beta_distribution(static_cast(1), static_cast(1))), std::domain_error); @@ -497,7 +511,19 @@ void test_spots(RealType) BOOST_MATH_CHECK_THROW(quantile(dist, -1), std::domain_error); BOOST_MATH_CHECK_THROW(quantile(complement(dist, -1)), std::domain_error); - // No longer allow any parameter to be NaN or inf, so all these tests should throw. + BOOST_MATH_CHECK_THROW(pdf(beta_distribution(static_cast(0.5), static_cast(1.5)), static_cast(0)), std::overflow_error); // alpha < 1, x = 0 + BOOST_MATH_CHECK_THROW(pdf(beta_distribution(static_cast(1.5), static_cast(0.5)), static_cast(1)), std::overflow_error); // beta < 1, x = 1 + + // There aren't any upper bounds on the mean/variance. Should we add these? + test_find_alpha_beta(static_cast(-1), static_cast(1)); // mean < 0 + test_find_alpha_beta(static_cast(-1), static_cast(-1)); // var < 0 + + test_find_alpha_beta(static_cast(1), static_cast(0.5), static_cast(-0.5)); // p < 0 + test_find_alpha_beta(static_cast(1), static_cast(0.5), static_cast(1.5)); // p > 0 + test_find_alpha_beta(static_cast(1), static_cast(1.5), static_cast(0.5)); // x > 0 + test_find_alpha_beta(static_cast(1), static_cast(-0.5), static_cast(0.5)); // x < 0 + + // No longer allow any parameter to be NaN or inf, so all these tests should throw. if (std::numeric_limits::has_quiet_NaN) { // Attempt to construct from non-finite should throw. @@ -545,6 +571,37 @@ void test_spots(RealType) BOOST_MATH_CHECK_THROW(cdf(complement(w, +inf)), std::domain_error); // x = + inf BOOST_MATH_CHECK_THROW(quantile(w, +inf), std::domain_error); // p = + inf BOOST_MATH_CHECK_THROW(quantile(complement(w, +inf)), std::domain_error); // p = + inf + + test_find_alpha_beta(static_cast(1), static_cast(0.5), inf); // p = inf + test_find_alpha_beta(inf, static_cast(0.5)); // mean = inf + test_find_alpha_beta(static_cast(0.5), inf); // var = inf + test_find_alpha_beta(static_cast(1), inf, static_cast(0.5)); // x = inf + + // Check isnan policies + using boost::math::policies::policy; + + typedef policy< + boost::math::policies::domain_error, + boost::math::policies::overflow_error, + boost::math::policies::underflow_error, + boost::math::policies::denorm_error, + boost::math::policies::pole_error, + boost::math::policies::evaluation_error + > ignore_all_policy; + + typedef beta_distribution ignore_error_beta; + + BOOST_CHECK((boost::math::isnan)(ignore_error_beta::find_alpha(inf, static_cast(0.5)))); // mean = inf + BOOST_CHECK((boost::math::isnan)(ignore_error_beta::find_beta(inf, static_cast(0.5)))); // mean = inf + BOOST_CHECK((boost::math::isnan)(ignore_error_beta::find_alpha(inf, static_cast(0.5), static_cast(0.5)))); // beta = inf + BOOST_CHECK((boost::math::isnan)(ignore_error_beta::find_beta(inf, static_cast(0.5), static_cast(0.5)))); // alpha = inf + BOOST_CHECK((boost::math::isnan)(mode(ignore_error_beta(static_cast(2), static_cast(1))))); // beta = 1 + BOOST_CHECK((boost::math::isnan)(mode(ignore_error_beta(static_cast(1), static_cast(2))))); // alpha = 1 + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_beta(static_cast(1), static_cast(1)), 2))); // x > 1 + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_beta(static_cast(1), static_cast(1)), 2))); // x > 1 + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_beta(static_cast(1), static_cast(1)), 2)))); // x > 1 + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_beta(static_cast(1), static_cast(1)), 2))); // p > 1 + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_beta(static_cast(1), static_cast(1)), 2)))); // p > 1 } // has_infinity // Error handling checks: @@ -600,6 +657,8 @@ BOOST_AUTO_TEST_CASE( test_main ) BOOST_CHECK_CLOSE_FRACTION(cdf(mybeta11, 0.5), 0.5, 2 * std::numeric_limits::epsilon()); BOOST_CHECK_CLOSE_FRACTION(cdf(mybeta11, 0.9), 0.9, 2 * std::numeric_limits::epsilon()); BOOST_CHECK_EQUAL(cdf(mybeta11, 1), 1.); // Exact unity expected. + BOOST_CHECK_EQUAL(cdf(complement(mybeta11, 1)), 0.0); // Exact 0 expected. + BOOST_CHECK_EQUAL(cdf(complement(mybeta11, 0)), 1.0); // Exact unity expected. double tol = std::numeric_limits::epsilon() * 10; BOOST_CHECK_EQUAL(pdf(mybeta22, 1), 0); // is dome shape. @@ -627,6 +686,11 @@ BOOST_AUTO_TEST_CASE( test_main ) // quantile. BOOST_CHECK_CLOSE_FRACTION(quantile(mybeta22, 0.028), 0.1, tol); BOOST_CHECK_CLOSE_FRACTION(quantile(complement(mybeta22, 1 - 0.028)), 0.1, tol); + BOOST_CHECK_EQUAL(quantile(mybeta22, 0), 0.); + BOOST_CHECK_EQUAL(quantile(mybeta22, 1), 1.); + BOOST_CHECK_EQUAL(quantile(complement(mybeta22, 0)), 1.); + BOOST_CHECK_EQUAL(quantile(complement(mybeta22, 1)), 0.); + BOOST_CHECK_EQUAL(kurtosis(mybeta11), 3+ kurtosis_excess(mybeta11)); // Check kurtosis_excess = kurtosis - 3; BOOST_CHECK_CLOSE_FRACTION(variance(mybeta22), 0.05, tol); BOOST_CHECK_CLOSE_FRACTION(mean(mybeta22), 0.5, tol); From 96f7df8e25d93b0e74dde886e3007427e1dd30da Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Tue, 26 May 2026 11:43:58 -0700 Subject: [PATCH 4/7] Added som basic binomial tests --- include/boost/math/distributions/binomial.hpp | 20 +++--- test/test_binomial.cpp | 67 +++++++++++++++++++ 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/include/boost/math/distributions/binomial.hpp b/include/boost/math/distributions/binomial.hpp index 93b148eac8..f2a800aeac 100644 --- a/include/boost/math/distributions/binomial.hpp +++ b/include/boost/math/distributions/binomial.hpp @@ -88,7 +88,7 @@ #include // error checks #include // isnan. #include // for root finding. - +#include #include namespace boost @@ -157,7 +157,7 @@ namespace boost template BOOST_MATH_CUDA_ENABLED inline bool check_dist_and_prob(const char* function, const RealType& N, RealType p, RealType prob, RealType* result, const Policy& pol) { - if((check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false) + if(!(check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol))) return false; return true; } @@ -321,11 +321,11 @@ namespace boost BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_lower_bound_on_p"; // Error checks: RealType result = 0; - if(false == binomial_detail::check_dist_and_k( + if(!(binomial_detail::check_dist_and_k( function, trials, RealType(0), successes, &result, Policy()) && binomial_detail::check_dist_and_prob( - function, trials, RealType(0), probability, &result, Policy())) + function, trials, RealType(0), probability, &result, Policy()))) { return result; } if(successes == 0) @@ -346,11 +346,11 @@ namespace boost BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_upper_bound_on_p"; // Error checks: RealType result = 0; - if(false == binomial_detail::check_dist_and_k( + if(!(binomial_detail::check_dist_and_k( function, trials, RealType(0), successes, &result, Policy()) && binomial_detail::check_dist_and_prob( - function, trials, RealType(0), probability, &result, Policy())) + function, trials, RealType(0), probability, &result, Policy()))) { return result; } if(trials == successes) @@ -373,11 +373,11 @@ namespace boost BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_minimum_number_of_trials"; // Error checks: RealType result = 0; - if(false == binomial_detail::check_dist_and_k( + if(!(binomial_detail::check_dist_and_k( function, k, p, k, &result, Policy()) && binomial_detail::check_dist_and_prob( - function, k, p, alpha, &result, Policy())) + function, k, p, alpha, &result, Policy()))) { return result; } result = ibetac_invb(k + 1, p, alpha, Policy()); // returns n - k @@ -392,11 +392,11 @@ namespace boost BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_maximum_number_of_trials"; // Error checks: RealType result = 0; - if(false == binomial_detail::check_dist_and_k( + if(!(binomial_detail::check_dist_and_k( function, k, p, k, &result, Policy()) && binomial_detail::check_dist_and_prob( - function, k, p, alpha, &result, Policy())) + function, k, p, alpha, &result, Policy()))) { return result; } result = ibeta_invb(k + 1, p, alpha, Policy()); // returns n - k diff --git a/test/test_binomial.cpp b/test/test_binomial.cpp index ef7f171723..45027aa823 100644 --- a/test/test_binomial.cpp +++ b/test/test_binomial.cpp @@ -599,7 +599,74 @@ void test_spots(RealType T) binomial_distribution(static_cast(8), static_cast(1)), static_cast(7)), static_cast(0) ); + BOOST_CHECK_EQUAL( + cdf( + complement(binomial_distribution(static_cast(8), static_cast(0)), + static_cast(7))), static_cast(0) + ); + BOOST_CHECK_EQUAL( + cdf( + complement(binomial_distribution(static_cast(8), static_cast(1)), + static_cast(7))), static_cast(1) + ); + // Check Error handling and edge cases + BOOST_CHECK_EQUAL(binomial_distribution::find_lower_bound_on_p(static_cast(5), + static_cast(0), + static_cast(0.5)), + static_cast(0)); // success = 0 + BOOST_CHECK_THROW(binomial_distribution::find_lower_bound_on_p(static_cast(5), + static_cast(2), + static_cast(-0.5)), + std::domain_error); // probability < 0 + BOOST_CHECK_THROW(binomial_distribution::find_lower_bound_on_p(static_cast(5), + static_cast(2), + static_cast(1.5)), + std::domain_error); // probability > 1 + BOOST_CHECK_EQUAL(binomial_distribution::find_upper_bound_on_p(static_cast(5), + static_cast(5), + static_cast(0.5)), + static_cast(1)); // trials = successes + BOOST_CHECK_THROW(binomial_distribution::find_upper_bound_on_p(static_cast(5), + static_cast(2), + static_cast(-0.5)), + std::domain_error); // probability < 0 + BOOST_CHECK_THROW(binomial_distribution::find_upper_bound_on_p(static_cast(5), + static_cast(2), + static_cast(1.5)), + std::domain_error); // probability > 1 + BOOST_CHECK_THROW(binomial_distribution::find_minimum_number_of_trials(static_cast(10), + static_cast(1.5), + static_cast(0.05)), + std::domain_error); // probability > 1 + BOOST_CHECK_THROW(binomial_distribution::find_minimum_number_of_trials(static_cast(10), + static_cast(-1), + static_cast(0.05)), + std::domain_error); // probability < 0 + BOOST_CHECK_THROW(binomial_distribution::find_minimum_number_of_trials(static_cast(10), + static_cast(0.5), + static_cast(-0.05)), + std::domain_error); // alpha < 0 + BOOST_CHECK_THROW(binomial_distribution::find_minimum_number_of_trials(static_cast(10), + static_cast(0.5), + static_cast(1.314)), + std::domain_error); // alpha > 1 + BOOST_CHECK_THROW(binomial_distribution::find_maximum_number_of_trials(static_cast(10), + static_cast(1.5), + static_cast(0.05)), + std::domain_error); // probability > 1 + BOOST_CHECK_THROW(binomial_distribution::find_maximum_number_of_trials(static_cast(10), + static_cast(-1), + static_cast(0.05)), + std::domain_error); // probability < 0 + BOOST_CHECK_THROW(binomial_distribution::find_maximum_number_of_trials(static_cast(10), + static_cast(0.5), + static_cast(-0.05)), + std::domain_error); // alpha < 0 + BOOST_CHECK_THROW(binomial_distribution::find_maximum_number_of_trials(static_cast(10), + static_cast(0.5), + static_cast(1.5)), + std::domain_error); // alpha > 1 #endif { From f2b43c29df778f10f9e3a9633b58df9d98f1e565 Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Tue, 26 May 2026 12:48:04 -0700 Subject: [PATCH 5/7] Added nan handling for binomial distribution --- include/boost/math/distributions/binomial.hpp | 2 +- test/test_binomial.cpp | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/boost/math/distributions/binomial.hpp b/include/boost/math/distributions/binomial.hpp index f2a800aeac..262823170f 100644 --- a/include/boost/math/distributions/binomial.hpp +++ b/include/boost/math/distributions/binomial.hpp @@ -88,7 +88,7 @@ #include // error checks #include // isnan. #include // for root finding. -#include + #include namespace boost diff --git a/test/test_binomial.cpp b/test/test_binomial.cpp index 45027aa823..b76c8e03e4 100644 --- a/test/test_binomial.cpp +++ b/test/test_binomial.cpp @@ -667,6 +667,43 @@ void test_spots(RealType T) static_cast(0.5), static_cast(1.5)), std::domain_error); // alpha > 1 + + if (std::numeric_limits::has_infinity) + { + // Check isnan policies + using boost::math::policies::policy; + + typedef policy< + boost::math::policies::domain_error, + boost::math::policies::overflow_error, + boost::math::policies::underflow_error, + boost::math::policies::denorm_error, + boost::math::policies::pole_error, + boost::math::policies::evaluation_error + > ignore_all_policy; + + typedef binomial_distribution ignore_error_binomial; + + BOOST_CHECK((boost::math::isnan)(ignore_error_binomial::find_lower_bound_on_p(static_cast(5), + static_cast(2), + static_cast(-0.5)))); // probability < 0 + BOOST_CHECK((boost::math::isnan)(ignore_error_binomial::find_upper_bound_on_p(static_cast(5), + static_cast(2), + static_cast(-0.5)))); // probability < 0 + BOOST_CHECK((boost::math::isnan)(ignore_error_binomial::find_minimum_number_of_trials(static_cast(10), + static_cast(-1), + static_cast(0.05)))); // probability < 0 + BOOST_CHECK((boost::math::isnan)(ignore_error_binomial::find_maximum_number_of_trials(static_cast(10), + static_cast(-1), + static_cast(0.05)))); // probability < 0 + + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_binomial(static_cast(-8), static_cast(0.25)), static_cast(8)))); + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_binomial(static_cast(8), static_cast(-0.25)), static_cast(8)))); + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_binomial(static_cast(8), static_cast(0.25)), static_cast(9)))); + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_binomial(static_cast(8), static_cast(0.25)), static_cast(9)))); + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_binomial(static_cast(8), static_cast(0.25)), static_cast(9))))); + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_binomial(static_cast(8), static_cast(0.25)), static_cast(-1)))); + } #endif { From 2b07b7a3ecbb44fb78da985fd287e464b0b0b46e Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Tue, 26 May 2026 18:06:34 -0700 Subject: [PATCH 6/7] Added cauchy tests --- include/boost/math/distributions/cauchy.hpp | 18 +++---- test/test_cauchy.cpp | 56 ++++++++++++++++++++- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/include/boost/math/distributions/cauchy.hpp b/include/boost/math/distributions/cauchy.hpp index 00a9ac9ac9..5a19f499a3 100644 --- a/include/boost/math/distributions/cauchy.hpp +++ b/include/boost/math/distributions/cauchy.hpp @@ -57,11 +57,11 @@ BOOST_MATH_GPU_ENABLED RealType cdf_imp(const cauchy_distribution((complement) ? 1 : 0); } #endif - if(false == detail::check_x(function, x, &result, Policy())) + if(!detail::check_x(function, x, &result, Policy())) { // Catches x == NaN return result; } @@ -111,15 +111,15 @@ BOOST_MATH_GPU_ENABLED RealType quantile_imp( RealType result = 0; RealType location = dist.location(); RealType scale = dist.scale(); - if(false == detail::check_location(function, location, &result, Policy())) + if(!detail::check_location(function, location, &result, Policy())) { return result; } - if(false == detail::check_scale(function, scale, &result, Policy())) + if(!detail::check_scale(function, scale, &result, Policy())) { return result; } - if(false == detail::check_probability(function, p, &result, Policy())) + if(!detail::check_probability(function, p, &result, Policy())) { return result; } @@ -224,11 +224,11 @@ BOOST_MATH_GPU_ENABLED inline RealType pdf(const cauchy_distribution >(0, 1); // (All) valid constructor parameter values. - + if (std::numeric_limits::has_infinity) + { + BOOST_CHECK_EQUAL( + boost::math::pdf( + cauchy_distribution(-2, 0.25), + std::numeric_limits::infinity()), // x + static_cast(0) // probability + ); + BOOST_CHECK_EQUAL( + boost::math::cdf( + cauchy_distribution(-2, 0.25), + std::numeric_limits::infinity()), // x + static_cast(1) // probability + ); + BOOST_CHECK_EQUAL( + boost::math::cdf( + cauchy_distribution(-2, 0.25), + -std::numeric_limits::infinity()), // x + static_cast(0) // probability + ); + BOOST_CHECK_EQUAL( + boost::math::quantile( + cauchy_distribution(-2, 0.25), + static_cast(0.5)), // p + static_cast(-2) // location + ); + + using boost::math::policies::policy; + + typedef policy< + boost::math::policies::domain_error, + boost::math::policies::overflow_error, + boost::math::policies::underflow_error, + boost::math::policies::denorm_error, + boost::math::policies::pole_error, + boost::math::policies::evaluation_error + > ignore_all_policy; + + typedef boost::math::cauchy_distribution ignore_error_cauchy; + + // PDF + BOOST_CHECK((boost::math::isnan)(boost::math::pdf(ignore_error_cauchy(static_cast(0), static_cast(-1)), static_cast(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::pdf(ignore_error_cauchy(std::numeric_limits::infinity(), static_cast(1)), static_cast(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::pdf(ignore_error_cauchy(static_cast(0), static_cast(1)), std::numeric_limits::quiet_NaN()))); + + // CDF + BOOST_CHECK((boost::math::isnan)(boost::math::cdf(ignore_error_cauchy(static_cast(0), static_cast(-1)), static_cast(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::cdf(ignore_error_cauchy(std::numeric_limits::infinity(), static_cast(1)), static_cast(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::cdf(ignore_error_cauchy(static_cast(0), static_cast(1)), std::numeric_limits::quiet_NaN()))); + + // Quantile + BOOST_CHECK((boost::math::isnan)(boost::math::quantile(ignore_error_cauchy(static_cast(0), static_cast(-1)), static_cast(0.25)))); + BOOST_CHECK((boost::math::isnan)(boost::math::quantile(ignore_error_cauchy(std::numeric_limits::infinity(), static_cast(1)), static_cast(0.25)))); + BOOST_CHECK((boost::math::isnan)(boost::math::quantile(ignore_error_cauchy(static_cast(0), static_cast(1)), static_cast(-0.25)))); + } } // template void test_spots(RealType) From 5abd8a2a37885fb01400e101a3391e8b6da14007 Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Tue, 26 May 2026 18:46:05 -0700 Subject: [PATCH 7/7] Added chi_squared distribution --- .../boost/math/distributions/chi_squared.hpp | 14 ++++----- test/test_chi_squared.cpp | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/include/boost/math/distributions/chi_squared.hpp b/include/boost/math/distributions/chi_squared.hpp index 3944569e89..9823a2d555 100644 --- a/include/boost/math/distributions/chi_squared.hpp +++ b/include/boost/math/distributions/chi_squared.hpp @@ -103,7 +103,7 @@ BOOST_MATH_GPU_ENABLED RealType pdf(const chi_squared_distribution::find constexpr auto function = "boost::math::chi_squared_distribution<%1%>::find_degrees_of_freedom(%1%,%1%,%1%,%1%,%1%)"; // Check for domain errors: RealType error_result; - if(false == - detail::check_probability(function, alpha, &error_result, Policy()) - && detail::check_probability(function, beta, &error_result, Policy())) + if(!(detail::check_probability(function, alpha, &error_result, Policy()) + && detail::check_probability(function, beta, &error_result, Policy()))) { // Either probability is outside 0 to 1. return error_result; } diff --git a/test/test_chi_squared.cpp b/test/test_chi_squared.cpp index a64926ca58..360f6947de 100644 --- a/test/test_chi_squared.cpp +++ b/test/test_chi_squared.cpp @@ -546,6 +546,9 @@ void test_spots(RealType T) chi_squared_distribution(static_cast(8)), static_cast(1.1))), std::domain_error ); + BOOST_MATH_CHECK_THROW( + mode(chi_squared_distribution(static_cast(1))), std::domain_error + ); // This first test value is taken from an example here: // http://www.itl.nist.gov/div898/handbook/prc/section2/prc232.htm @@ -566,6 +569,32 @@ void test_spots(RealType T) check_out_of_range >(1); // (All) valid constructor parameter values. + // NaN handling + if (std::numeric_limits::has_infinity) + { + using boost::math::policies::policy; + + typedef policy< + boost::math::policies::domain_error, + boost::math::policies::overflow_error, + boost::math::policies::underflow_error, + boost::math::policies::denorm_error, + boost::math::policies::pole_error, + boost::math::policies::evaluation_error + > ignore_all_policy; + + typedef boost::math::chi_squared_distribution ignore_error_chi_squared; + + BOOST_CHECK((boost::math::isnan)(pdf(ignore_error_chi_squared(static_cast(-1)), static_cast(1)))); + BOOST_CHECK((boost::math::isnan)(cdf(ignore_error_chi_squared(static_cast(-1)), static_cast(1)))); + BOOST_CHECK((boost::math::isnan)(cdf(complement(ignore_error_chi_squared(static_cast(-1)), static_cast(1))))); + BOOST_CHECK((boost::math::isnan)(quantile(ignore_error_chi_squared(static_cast(-1)), static_cast(0.5)))); + BOOST_CHECK((boost::math::isnan)(quantile(complement(ignore_error_chi_squared(static_cast(-1)), static_cast(0.5))))); + BOOST_CHECK((boost::math::isnan)(mode(ignore_error_chi_squared(static_cast(1))))); + BOOST_CHECK((boost::math::isnan)(ignore_error_chi_squared::find_degrees_of_freedom(10, -1, 0.01f, 100))); + BOOST_CHECK((boost::math::isnan)(ignore_error_chi_squared::find_degrees_of_freedom(10, 0.05f, -1, 100))); + + } } // template void test_spots(RealType) BOOST_AUTO_TEST_CASE( test_main )