From 8762d35b2dc8bb271075181ae45fb46db13d1fde Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Mon, 15 Jun 2026 20:07:59 -0700 Subject: [PATCH 1/4] Initial implementation of fisher_f degrees of freedom finder --- include/boost/math/distributions/fisher_f.hpp | 166 +++++++++++++++++- .../math/distributions/non_central_f.hpp | 8 +- 2 files changed, 168 insertions(+), 6 deletions(-) diff --git a/include/boost/math/distributions/fisher_f.hpp b/include/boost/math/distributions/fisher_f.hpp index 56b288d88e..73e2db1b16 100644 --- a/include/boost/math/distributions/fisher_f.hpp +++ b/include/boost/math/distributions/fisher_f.hpp @@ -17,7 +17,84 @@ #include // error checks #include -namespace boost{ namespace math{ +namespace boost{ namespace math{ + namespace detail{ + template + struct fisher_degrees_of_freedom_finder + { + fisher_degrees_of_freedom_finder( + RealType x_, RealType v_, bool find_v1_, RealType p_, bool c) + : x(x_), v(v_), find_v1(find_v1_), p(p_), comp(c) {} + + RealType operator()(const RealType& input_v) + { + RealType v1 = find_v1 ? input_v : v; + RealType v2 = find_v1 ? v : input_v; + fisher_f_distribution d(v1, v2); + return comp ? + p - cdf(complement(d, x)) + : cdf(d, x) - p; + } + private: + RealType x; + RealType v; + bool find_v1; + RealType p; + bool comp; + }; + + template + inline RealType find_degrees_of_freedom_fisher_f( + const RealType x, const RealType v, const RealType nc, const bool find_v1, const RealType p, const RealType q, const Policy& pol) + { + BOOST_MATH_STD_USING + using std::fabs; + const char* function = "fisher_f_distribution<%1%>::find_degrees_of_freedom_f"; + if((p == 0) || (q == 0)) + { + // + // Can't find a thing if one of p and q is zero: + // + return policies::raise_domain_error(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", + RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE + } + if (x < tools::epsilon()) + { + return policies::raise_evaluation_error(function, "Can't find degrees of freedom when the abscissa value is very close to zero as all degrees of freedom generate the same CDF at x=0: try again further out in the tails!!", + RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE + } + fisher_degrees_of_freedom_finder f(x, v, find_v1, p < q ? p : q, p < q ? false : true); + + // There are times when f has two roots - thus, two degrees of freedom can + // be found. We find this case by checking if the sign of f for large and + // small values of v have the same sign. If the sign is the same, then there + // are an even number of roots. If the signs differ, there is only one root + // and we can safely find the root. + RealType vLarge = sqrt(boost::math::tools::max_value()); + RealType vSmall = 1 / vLarge; + + if ((f(vLarge) < 0) == (f(vSmall) < 0)){ + return policies::raise_evaluation_error(function, "Can't find degrees of freedom because two degrees of freedom can be found using the given parameters", + RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE + } + + tools::eps_tolerance tol(policies::digits()); + std::uintmax_t max_iter = policies::get_max_root_iterations(); + // + // Pick an initial guess: + // + RealType guess = 1; + std::pair ir = tools::bracket_and_solve_root( + f, guess, RealType(2), f(guess) < 0 ? true : false, tol, max_iter, pol); + RealType result = ir.first + (ir.second - ir.first) / 2; + if(max_iter >= policies::get_max_root_iterations()) + { + return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE + " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE + } + return result; + } + } template > class fisher_f_distribution @@ -44,7 +121,92 @@ class fisher_f_distribution { return m_df2; } - + BOOST_MATH_GPU_ENABLED static RealType find_v1(const RealType x, const RealType v2, const RealType p) + { + constexpr auto function = "fisher_f_distribution<%1%>::find_v1"; + typedef typename policies::evaluation::type eval_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + eval_type result = detail::find_degrees_of_freedom_fisher_f( + static_cast(x), + static_cast(v2), + true, + static_cast(p), + static_cast(1-p), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + template + BOOST_MATH_GPU_ENABLED static RealType find_v1(const complemented4_type& c) + { + constexpr auto function = "fisher_f_distribution<%1%>::find_non_centrality"; + typedef typename policies::evaluation::type eval_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + eval_type result = detail::find_degrees_of_freedom_fisher_f( + static_cast(c.dist), + static_cast(c.param1), + true, + static_cast(1-c.param2), + static_cast(c.param2), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + BOOST_MATH_GPU_ENABLED static RealType find_v2(const RealType x, const RealType v2, const RealType p) + { + constexpr auto function = "fisher_f_distribution<%1%>::find_v1"; + typedef typename policies::evaluation::type eval_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + eval_type result = detail::find_degrees_of_freedom_fisher_f( + static_cast(x), + static_cast(v2), + false, + static_cast(p), + static_cast(1-p), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + template + BOOST_MATH_GPU_ENABLED static RealType find_v2(const complemented4_type& c) + { + constexpr auto function = "fisher_f_distribution<%1%>::find_v2"; + typedef typename policies::evaluation::type eval_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + eval_type result = detail::find_degrees_of_freedom_fisher_f( + static_cast(c.dist), + static_cast(c.param1), + false, + static_cast(1-c.param2), + static_cast(c.param2), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } private: // // Data members: diff --git a/include/boost/math/distributions/non_central_f.hpp b/include/boost/math/distributions/non_central_f.hpp index 9bae5c41ff..6a53a3f1d3 100644 --- a/include/boost/math/distributions/non_central_f.hpp +++ b/include/boost/math/distributions/non_central_f.hpp @@ -287,7 +287,7 @@ namespace boost template BOOST_MATH_GPU_ENABLED static RealType find_v1(const complemented4_type& c) { - constexpr auto function = "non_central_f_distribution<%1%>::find_non_centrality"; + constexpr auto function = "non_central_f_distribution<%1%>::find_v1"; typedef typename policies::evaluation::type eval_type; typedef typename policies::normalise< Policy, @@ -307,9 +307,9 @@ namespace boost result, function); } - BOOST_MATH_GPU_ENABLED static RealType find_v2(const RealType x, const RealType v2, const RealType nc, const RealType p) + BOOST_MATH_GPU_ENABLED static RealType find_v2(const RealType x, const RealType v2, const RealType nc, const RealType p) { - constexpr auto function = "non_central_f_distribution<%1%>::find_v1"; + constexpr auto function = "non_central_f_distribution<%1%>::find_v2"; typedef typename policies::evaluation::type eval_type; typedef typename policies::normalise< Policy, @@ -332,7 +332,7 @@ namespace boost template BOOST_MATH_GPU_ENABLED static RealType find_v2(const complemented4_type& c) { - constexpr auto function = "non_central_f_distribution<%1%>::find_non_centrality"; + constexpr auto function = "non_central_f_distribution<%1%>::find_v2"; typedef typename policies::evaluation::type eval_type; typedef typename policies::normalise< Policy, From 7c96a2a0eb2ce293e51172fee39bb5186006d28b Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Mon, 15 Jun 2026 20:35:41 -0700 Subject: [PATCH 2/4] Refined implementation ot use special case of nc=0 --- include/boost/math/distributions/fisher_f.hpp | 98 +++---------------- .../math/distributions/non_central_f.hpp | 14 +++ 2 files changed, 27 insertions(+), 85 deletions(-) diff --git a/include/boost/math/distributions/fisher_f.hpp b/include/boost/math/distributions/fisher_f.hpp index 73e2db1b16..6ced557d4a 100644 --- a/include/boost/math/distributions/fisher_f.hpp +++ b/include/boost/math/distributions/fisher_f.hpp @@ -16,85 +16,9 @@ #include // complements #include // error checks #include +#include // for find_degrees_of_freedom_f namespace boost{ namespace math{ - namespace detail{ - template - struct fisher_degrees_of_freedom_finder - { - fisher_degrees_of_freedom_finder( - RealType x_, RealType v_, bool find_v1_, RealType p_, bool c) - : x(x_), v(v_), find_v1(find_v1_), p(p_), comp(c) {} - - RealType operator()(const RealType& input_v) - { - RealType v1 = find_v1 ? input_v : v; - RealType v2 = find_v1 ? v : input_v; - fisher_f_distribution d(v1, v2); - return comp ? - p - cdf(complement(d, x)) - : cdf(d, x) - p; - } - private: - RealType x; - RealType v; - bool find_v1; - RealType p; - bool comp; - }; - - template - inline RealType find_degrees_of_freedom_fisher_f( - const RealType x, const RealType v, const RealType nc, const bool find_v1, const RealType p, const RealType q, const Policy& pol) - { - BOOST_MATH_STD_USING - using std::fabs; - const char* function = "fisher_f_distribution<%1%>::find_degrees_of_freedom_f"; - if((p == 0) || (q == 0)) - { - // - // Can't find a thing if one of p and q is zero: - // - return policies::raise_domain_error(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", - RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE - } - if (x < tools::epsilon()) - { - return policies::raise_evaluation_error(function, "Can't find degrees of freedom when the abscissa value is very close to zero as all degrees of freedom generate the same CDF at x=0: try again further out in the tails!!", - RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE - } - fisher_degrees_of_freedom_finder f(x, v, find_v1, p < q ? p : q, p < q ? false : true); - - // There are times when f has two roots - thus, two degrees of freedom can - // be found. We find this case by checking if the sign of f for large and - // small values of v have the same sign. If the sign is the same, then there - // are an even number of roots. If the signs differ, there is only one root - // and we can safely find the root. - RealType vLarge = sqrt(boost::math::tools::max_value()); - RealType vSmall = 1 / vLarge; - - if ((f(vLarge) < 0) == (f(vSmall) < 0)){ - return policies::raise_evaluation_error(function, "Can't find degrees of freedom because two degrees of freedom can be found using the given parameters", - RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE - } - - tools::eps_tolerance tol(policies::digits()); - std::uintmax_t max_iter = policies::get_max_root_iterations(); - // - // Pick an initial guess: - // - RealType guess = 1; - std::pair ir = tools::bracket_and_solve_root( - f, guess, RealType(2), f(guess) < 0 ? true : false, tol, max_iter, pol); - RealType result = ir.first + (ir.second - ir.first) / 2; - if(max_iter >= policies::get_max_root_iterations()) - { - return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE - " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE - } - return result; - } - } template > class fisher_f_distribution @@ -131,9 +55,10 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_fisher_f( + eval_type result = detail::find_degrees_of_freedom_f( static_cast(x), static_cast(v2), + static_cast(0), // nc=0 true, static_cast(p), static_cast(1-p), @@ -143,9 +68,9 @@ class fisher_f_distribution function); } template - BOOST_MATH_GPU_ENABLED static RealType find_v1(const complemented4_type& c) + BOOST_MATH_GPU_ENABLED static RealType find_v1(const complemented3_type& c) { - constexpr auto function = "fisher_f_distribution<%1%>::find_non_centrality"; + constexpr auto function = "fisher_f_distribution<%1%>::find_v1"; typedef typename policies::evaluation::type eval_type; typedef typename policies::normalise< Policy, @@ -153,9 +78,10 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_fisher_f( + eval_type result = detail::find_degrees_of_freedom_f( static_cast(c.dist), static_cast(c.param1), + static_cast(0), // nc=0 true, static_cast(1-c.param2), static_cast(c.param2), @@ -166,7 +92,7 @@ class fisher_f_distribution } BOOST_MATH_GPU_ENABLED static RealType find_v2(const RealType x, const RealType v2, const RealType p) { - constexpr auto function = "fisher_f_distribution<%1%>::find_v1"; + constexpr auto function = "fisher_f_distribution<%1%>::find_v2"; typedef typename policies::evaluation::type eval_type; typedef typename policies::normalise< Policy, @@ -174,9 +100,10 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_fisher_f( + eval_type result = detail::find_degrees_of_freedom_f( static_cast(x), static_cast(v2), + static_cast(0), // nc=0 false, static_cast(p), static_cast(1-p), @@ -186,7 +113,7 @@ class fisher_f_distribution function); } template - BOOST_MATH_GPU_ENABLED static RealType find_v2(const complemented4_type& c) + BOOST_MATH_GPU_ENABLED static RealType find_v2(const complemented3_type& c) { constexpr auto function = "fisher_f_distribution<%1%>::find_v2"; typedef typename policies::evaluation::type eval_type; @@ -196,9 +123,10 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_fisher_f( + eval_type result = detail::find_degrees_of_freedom_f( static_cast(c.dist), static_cast(c.param1), + static_cast(0), // nc=0 false, static_cast(1-c.param2), static_cast(c.param2), diff --git a/include/boost/math/distributions/non_central_f.hpp b/include/boost/math/distributions/non_central_f.hpp index 6a53a3f1d3..ccddb05226 100644 --- a/include/boost/math/distributions/non_central_f.hpp +++ b/include/boost/math/distributions/non_central_f.hpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -94,6 +96,13 @@ namespace boost { RealType v1 = find_v1 ? input_v : v; RealType v2 = find_v1 ? v : input_v; + if (nc == 0) + { + fisher_f_distribution d(v1, v2); + return comp ? + p - cdf(complement(d, x)) + : cdf(d, x) - p; + } non_central_f_distribution d(v1, v2, nc); return comp ? p - cdf(complement(d, x)) @@ -114,6 +123,11 @@ namespace boost // with degrees of freedom v1 at the cdf at x * v1 bool comp = p < q ? false : true; RealType pval = p < q ? p : q; + if (nc == 0) + { + chi_squared_distribution d(v1); + return comp ? pval - cdf(complement(d, x*v1)) : cdf(d, x*v1) - pval; + } non_central_chi_squared_distribution d(v1, nc); return comp ? pval - cdf(complement(d, x*v1)) : cdf(d, x*v1) - pval; } From 512a55de108457c3cdd652bd4006e5196bc72ff8 Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Tue, 16 Jun 2026 20:10:40 -0700 Subject: [PATCH 3/4] Reverted to initial changes --- include/boost/math/distributions/fisher_f.hpp | 90 +++++++++++++++++-- .../math/distributions/non_central_f.hpp | 14 --- 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/include/boost/math/distributions/fisher_f.hpp b/include/boost/math/distributions/fisher_f.hpp index 6ced557d4a..0294c48360 100644 --- a/include/boost/math/distributions/fisher_f.hpp +++ b/include/boost/math/distributions/fisher_f.hpp @@ -16,9 +16,85 @@ #include // complements #include // error checks #include -#include // for find_degrees_of_freedom_f namespace boost{ namespace math{ + namespace detail{ + template + struct fisher_degrees_of_freedom_finder + { + fisher_degrees_of_freedom_finder( + RealType x_, RealType v_, bool find_v1_, RealType p_, bool c) + : x(x_), v(v_), find_v1(find_v1_), p(p_), comp(c) {} + + RealType operator()(const RealType& input_v) + { + RealType v1 = find_v1 ? input_v : v; + RealType v2 = find_v1 ? v : input_v; + fisher_f_distribution d(v1, v2); + return comp ? + p - cdf(complement(d, x)) + : cdf(d, x) - p; + } + private: + RealType x; + RealType v; + bool find_v1; + RealType p; + bool comp; + }; + + template + inline RealType find_degrees_of_freedom_fisher_f( + const RealType x, const RealType v, const RealType nc, const bool find_v1, const RealType p, const RealType q, const Policy& pol) + { + BOOST_MATH_STD_USING + using std::fabs; + const char* function = "fisher_f_distribution<%1%>::find_degrees_of_freedom_f"; + if((p == 0) || (q == 0)) + { + // + // Can't find a thing if one of p and q is zero: + // + return policies::raise_domain_error(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", + RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE + } + if (x < tools::epsilon()) + { + return policies::raise_evaluation_error(function, "Can't find degrees of freedom when the abscissa value is very close to zero as all degrees of freedom generate the same CDF at x=0: try again further out in the tails!!", + RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE + } + fisher_degrees_of_freedom_finder f(x, v, find_v1, p < q ? p : q, p < q ? false : true); + + // There are times when f has two roots - thus, two degrees of freedom can + // be found. We find this case by checking if the sign of f for large and + // small values of v have the same sign. If the sign is the same, then there + // are an even number of roots. If the signs differ, there is only one root + // and we can safely find the root. + RealType vLarge = sqrt(boost::math::tools::max_value()); + RealType vSmall = 1 / vLarge; + + if ((f(vLarge) < 0) == (f(vSmall) < 0)){ + return policies::raise_evaluation_error(function, "Can't find degrees of freedom because two degrees of freedom can be found using the given parameters", + RealType(std::numeric_limits::quiet_NaN()), Policy()); // LCOV_EXCL_LINE + } + + tools::eps_tolerance tol(policies::digits()); + std::uintmax_t max_iter = policies::get_max_root_iterations(); + // + // Pick an initial guess: + // + RealType guess = 1; + std::pair ir = tools::bracket_and_solve_root( + f, guess, RealType(2), f(guess) < 0 ? true : false, tol, max_iter, pol); + RealType result = ir.first + (ir.second - ir.first) / 2; + if(max_iter >= policies::get_max_root_iterations()) + { + return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE + " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE + } + return result; + } + } template > class fisher_f_distribution @@ -55,10 +131,9 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_f( + eval_type result = detail::find_degrees_of_freedom_fisher_f( static_cast(x), static_cast(v2), - static_cast(0), // nc=0 true, static_cast(p), static_cast(1-p), @@ -78,10 +153,9 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_f( + eval_type result = detail::find_degrees_of_freedom_fisher_f( static_cast(c.dist), static_cast(c.param1), - static_cast(0), // nc=0 true, static_cast(1-c.param2), static_cast(c.param2), @@ -100,10 +174,9 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_f( + eval_type result = detail::find_degrees_of_freedom_fisher_f( static_cast(x), static_cast(v2), - static_cast(0), // nc=0 false, static_cast(p), static_cast(1-p), @@ -123,10 +196,9 @@ class fisher_f_distribution policies::promote_double, policies::discrete_quantile<>, policies::assert_undefined<> >::type forwarding_policy; - eval_type result = detail::find_degrees_of_freedom_f( + eval_type result = detail::find_degrees_of_freedom_fisher_f( static_cast(c.dist), static_cast(c.param1), - static_cast(0), // nc=0 false, static_cast(1-c.param2), static_cast(c.param2), diff --git a/include/boost/math/distributions/non_central_f.hpp b/include/boost/math/distributions/non_central_f.hpp index ccddb05226..6a53a3f1d3 100644 --- a/include/boost/math/distributions/non_central_f.hpp +++ b/include/boost/math/distributions/non_central_f.hpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include #include @@ -96,13 +94,6 @@ namespace boost { RealType v1 = find_v1 ? input_v : v; RealType v2 = find_v1 ? v : input_v; - if (nc == 0) - { - fisher_f_distribution d(v1, v2); - return comp ? - p - cdf(complement(d, x)) - : cdf(d, x) - p; - } non_central_f_distribution d(v1, v2, nc); return comp ? p - cdf(complement(d, x)) @@ -123,11 +114,6 @@ namespace boost // with degrees of freedom v1 at the cdf at x * v1 bool comp = p < q ? false : true; RealType pval = p < q ? p : q; - if (nc == 0) - { - chi_squared_distribution d(v1); - return comp ? pval - cdf(complement(d, x*v1)) : cdf(d, x*v1) - pval; - } non_central_chi_squared_distribution d(v1, nc); return comp ? pval - cdf(complement(d, x*v1)) : cdf(d, x*v1) - pval; } From a68f945cdfa611b605fccf446dbf94f17f7fda74 Mon Sep 17 00:00:00 2001 From: Jacob Hass Date: Wed, 17 Jun 2026 06:48:55 -0700 Subject: [PATCH 4/4] Fixed typos and added tests --- include/boost/math/distributions/fisher_f.hpp | 2 +- test/test_fisher_f.cpp | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/boost/math/distributions/fisher_f.hpp b/include/boost/math/distributions/fisher_f.hpp index 0294c48360..464d1cda46 100644 --- a/include/boost/math/distributions/fisher_f.hpp +++ b/include/boost/math/distributions/fisher_f.hpp @@ -45,7 +45,7 @@ namespace boost{ namespace math{ template inline RealType find_degrees_of_freedom_fisher_f( - const RealType x, const RealType v, const RealType nc, const bool find_v1, const RealType p, const RealType q, const Policy& pol) + const RealType x, const RealType v, const bool find_v1, const RealType p, const RealType q, const Policy& pol) { BOOST_MATH_STD_USING using std::fabs; diff --git a/test/test_fisher_f.cpp b/test/test_fisher_f.cpp index 0739dfbda2..37cabdafce 100644 --- a/test/test_fisher_f.cpp +++ b/test/test_fisher_f.cpp @@ -413,7 +413,19 @@ void test_spots(RealType) BOOST_CHECK_CLOSE( kurtosis(dist2) , static_cast(6272) * 12 / 3456 + 3, tol2); - // special cases: + + if (!std::is_same::value) + { + RealType df1 = 10; + RealType df2 = 2; + RealType x = 6; + RealType P = cdf(fisher_f_distribution(df1, df2), x); + BOOST_CHECK_CLOSE(fisher_f_distribution::find_v2(x, df1, P), df2, tol2*10); + BOOST_CHECK_CLOSE(fisher_f_distribution::find_v1(x, df2, P), df1, tol2*10); + BOOST_CHECK_CLOSE(fisher_f_distribution::find_v1(boost::math::complement(x, df2, 1-P)), df1, tol2*10); + BOOST_CHECK_CLOSE(fisher_f_distribution::find_v2(boost::math::complement(x, df1, 1-P)), df2, tol2*10); + } + // special cases: BOOST_MATH_CHECK_THROW( pdf( fisher_f_distribution(static_cast(1), static_cast(1)),