diff --git a/include/boost/math/special_functions/airy.hpp b/include/boost/math/special_functions/airy.hpp index 65114089a6..4219e5286e 100644 --- a/include/boost/math/special_functions/airy.hpp +++ b/include/boost/math/special_functions/airy.hpp @@ -187,7 +187,7 @@ BOOST_MATH_GPU_ENABLED T airy_ai_zero_imp(int m, const Policy& pol) // of decimal digits in the numeric type T, being at least 12. const int my_digits10 = static_cast(static_cast(policies::digits() * 0.301F)); - const std::uintmax_t iterations_allowed = static_cast((std::max)(12, my_digits10 * 2)); + const std::uintmax_t iterations_allowed = static_cast(BOOST_MATH_GPU_SAFE_MAX(12, my_digits10 * 2)); std::uintmax_t iterations_used = iterations_allowed; @@ -239,7 +239,7 @@ BOOST_MATH_GPU_ENABLED T airy_bi_zero_imp(int m, const Policy& pol) // of decimal digits in the numeric type T, being at least 12. const int my_digits10 = static_cast(static_cast(policies::digits() * 0.301F)); - const std::uintmax_t iterations_allowed = static_cast((std::max)(12, my_digits10 * 2)); + const std::uintmax_t iterations_allowed = static_cast(BOOST_MATH_GPU_SAFE_MAX(12, my_digits10 * 2)); std::uintmax_t iterations_used = iterations_allowed; diff --git a/include/boost/math/special_functions/beta.hpp b/include/boost/math/special_functions/beta.hpp index ada8213085..931a3c53dc 100644 --- a/include/boost/math/special_functions/beta.hpp +++ b/include/boost/math/special_functions/beta.hpp @@ -1132,7 +1132,7 @@ BOOST_MATH_GPU_ENABLED T binomial_ccdf(T n, T k, T x, T y, const Policy& pol) } template -T ibeta_large_ab(T a, T b, T x, T y, bool invert, bool normalised, const Policy& pol) +BOOST_MATH_GPU_ENABLED T ibeta_large_ab(T a, T b, T x, T y, bool invert, bool normalised, const Policy& pol) { // // Large arguments, symetric case, see https://dlmf.nist.gov/8.18 @@ -1571,11 +1571,11 @@ BOOST_MATH_GPU_ENABLED T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, b { // a and b both large: bool use_asym = false; - T ma = (std::max)(a, b); + T ma = BOOST_MATH_GPU_SAFE_MAX(a, b); T xa = ma == a ? x : y; T saddle = ma / (a + b); T powers = 0; - if ((ma > 1e-5f / tools::epsilon()) && (ma / (std::min)(a, b) < (xa < saddle ? 2 : 15))) + if ((ma > 1e-5f / tools::epsilon()) && (ma / BOOST_MATH_GPU_SAFE_MIN(a, b) < (xa < saddle ? 2 : 15))) { if (a == b) use_asym = true; diff --git a/include/boost/math/special_functions/detail/ibeta_inverse.hpp b/include/boost/math/special_functions/detail/ibeta_inverse.hpp index bbf7f482b8..2465a11ed6 100644 --- a/include/boost/math/special_functions/detail/ibeta_inverse.hpp +++ b/include/boost/math/special_functions/detail/ibeta_inverse.hpp @@ -683,16 +683,16 @@ BOOST_MATH_GPU_ENABLED T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* } else y = 1; - if((y > 1e-5) && (std::min)(a, b) < 1000) + if((y > 1e-5) && BOOST_MATH_GPU_SAFE_MIN(a, b) < 1000) { x = temme_method_3_ibeta_inverse(a, b, p, q, pol); y = 1 - x; } - else if ((y > 1e-5) && (std::min)(a, b) > 1000) + else if ((y > 1e-5) && BOOST_MATH_GPU_SAFE_MIN(a, b) > 1000) { // All options have failed, use the saddle point as a starting location: - x = (std::max)(a, b) / (a + b); - y = (std::min)(a, b) / (a + b); + x = BOOST_MATH_GPU_SAFE_MAX(a, b) / (a + b); + y = BOOST_MATH_GPU_SAFE_MIN(a, b) / (a + b); } } } diff --git a/include/boost/math/special_functions/expint.hpp b/include/boost/math/special_functions/expint.hpp index 314ae4bee5..eeec63199e 100644 --- a/include/boost/math/special_functions/expint.hpp +++ b/include/boost/math/special_functions/expint.hpp @@ -562,6 +562,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: // Maximum Deviation Found: 2.852e-18 // Expected Error Term: 2.852e-18 // Max Error found at double precision = Poly: 2.636335e-16 Cheb: 4.187027e-16 + // LCOV_EXCL_START BOOST_MATH_STATIC const T P[10] = { BOOST_MATH_BIG_CONSTANT(T, 53, 2.98677224343598593013), BOOST_MATH_BIG_CONSTANT(T, 53, 0.356343618769377415068), @@ -590,6 +591,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: BOOST_MATH_STATIC_LOCAL_VARIABLE const T r1 = static_cast(c1 / c2); BOOST_MATH_STATIC_LOCAL_VARIABLE const T r2 = BOOST_MATH_BIG_CONSTANT(T, 53, 0.131401834143860282009280387409357165515556574352422001206362e-16); BOOST_MATH_STATIC_LOCAL_VARIABLE const T r = static_cast(BOOST_MATH_BIG_CONSTANT(T, 53, 0.372507410781366634461991866580119133535689497771654051555657435242200120636201854384926049951548942392)); + // LCOV_EXCL_STOP T t = (z / 3) - 1; result = tools::evaluate_polynomial(P, t) / tools::evaluate_polynomial(Q, t); @@ -609,6 +611,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: // Maximum Deviation Found: 6.546e-17 // Expected Error Term: 6.546e-17 // Max Error found at double precision = Poly: 6.890169e-17 Cheb: 6.772128e-17 + // LCOV_EXCL_START BOOST_MATH_STATIC_LOCAL_VARIABLE const T Y = 1.158985137939453125F; BOOST_MATH_STATIC const T P[8] = { BOOST_MATH_BIG_CONSTANT(T, 53, 0.00139324086199402804173), @@ -630,6 +633,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: BOOST_MATH_BIG_CONSTANT(T, 53, 0.000402453408512476836472), BOOST_MATH_BIG_CONSTANT(T, 53, 0.263649630720255691787e-4) }; + // LCOV_EXCL_STOP T t = z / 2 - 4; result = Y + tools::evaluate_polynomial(P, t) / tools::evaluate_polynomial(Q, t); @@ -641,7 +645,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: // Maximum Deviation Found: 1.843e-17 // Expected Error Term: -1.842e-17 // Max Error found at double precision = Poly: 4.375868e-17 Cheb: 5.860967e-17 - + // LCOV_EXCL_START BOOST_MATH_STATIC_LOCAL_VARIABLE const T Y = 1.0869731903076171875F; BOOST_MATH_STATIC const T P[9] = { BOOST_MATH_BIG_CONSTANT(T, 53, -0.00893891094356945667451), @@ -665,6 +669,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: BOOST_MATH_BIG_CONSTANT(T, 53, 0.00278170769163303669021), BOOST_MATH_BIG_CONSTANT(T, 53, 0.000159150281166108755531) }; + // LCOV_EXCL_STOP T t = z / 5 - 3; result = Y + tools::evaluate_polynomial(P, t) / tools::evaluate_polynomial(Q, t); @@ -676,8 +681,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: // Maximum Deviation Found: 5.102e-18 // Expected Error Term: 5.101e-18 // Max Error found at double precision = Poly: 1.441088e-16 Cheb: 1.864792e-16 - - + // LCOV_EXCL_START BOOST_MATH_STATIC_LOCAL_VARIABLE const T Y = 1.03937530517578125F; BOOST_MATH_STATIC const T P[9] = { BOOST_MATH_BIG_CONSTANT(T, 53, -0.00356165148914447597995), @@ -700,6 +704,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: BOOST_MATH_BIG_CONSTANT(T, 53, 0.0651165455496281337831), BOOST_MATH_BIG_CONSTANT(T, 53, 0.00488071077519227853585) }; + // LCOV_EXCL_STOP T t = z / 10 - 3; result = Y + tools::evaluate_polynomial(P, t) / tools::evaluate_polynomial(Q, t); @@ -709,6 +714,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: else { // Max Error found at double precision = 3.381886e-17 + // LCOV_EXCL_START BOOST_MATH_STATIC_LOCAL_VARIABLE const T exp40 = static_cast(BOOST_MATH_BIG_CONSTANT(T, 53, 2.35385266837019985407899910749034804508871617254555467236651e17)); BOOST_MATH_STATIC_LOCAL_VARIABLE const T Y= 1.013065338134765625F; BOOST_MATH_STATIC const T P[6] = { @@ -728,6 +734,7 @@ BOOST_MATH_GPU_ENABLED T expint_i_imp(T z, const Policy& pol, const boost::math: BOOST_MATH_BIG_CONSTANT(T, 53, 54738.2833147775537106), BOOST_MATH_BIG_CONSTANT(T, 53, 8297.16296356518409347) }; + // LCOV_EXCL_STOP T t = 1 / z; result = Y + tools::evaluate_polynomial(P, t) / tools::evaluate_polynomial(Q, t); diff --git a/include/boost/math/special_functions/fpclassify.hpp b/include/boost/math/special_functions/fpclassify.hpp index 734241bbff..38eb5dbc93 100644 --- a/include/boost/math/special_functions/fpclassify.hpp +++ b/include/boost/math/special_functions/fpclassify.hpp @@ -127,7 +127,7 @@ template<> inline BOOST_MATH_GPU_ENABLED int (fpclassify)(float t) } else if(at > FLT_MAX) return FP_INFINITE; - return FP_NAN; + return FP_NAN; // LCOV_EXCL_LINE should not normally be reachable. } template<> inline BOOST_MATH_GPU_ENABLED int (fpclassify)(double t) diff --git a/include/boost/math/special_functions/jacobi_elliptic.hpp b/include/boost/math/special_functions/jacobi_elliptic.hpp index 114b991d9c..149e9fb1ca 100644 --- a/include/boost/math/special_functions/jacobi_elliptic.hpp +++ b/include/boost/math/special_functions/jacobi_elliptic.hpp @@ -41,9 +41,7 @@ T jacobi_imp(const T& x, const T& k, T* cn, T* dn, const Policy& pol, const char BOOST_MATH_STD_USING if(k < 0) { - *cn = policies::raise_domain_error(function, "Modulus k must be positive but got %1%.", k, pol); - *dn = *cn; - return *cn; + return *dn = *cn = policies::raise_domain_error(function, "Modulus k must be positive but got %1%.", k, pol); } if(k > 1) { diff --git a/include/boost/math/special_functions/jacobi_theta.hpp b/include/boost/math/special_functions/jacobi_theta.hpp index 39b1243913..e3e17e7e03 100644 --- a/include/boost/math/special_functions/jacobi_theta.hpp +++ b/include/boost/math/special_functions/jacobi_theta.hpp @@ -292,8 +292,7 @@ jacobi_theta1tau_imp(RealType z, RealType tau, const Policy& pol, const char *fu RealType q_n = 0, last_q_n, delta, result = 0; if (tau <= 0.0) - return policies::raise_domain_error(function, - "tau must be greater than 0 but got %1%.", tau, pol); + return policies::raise_domain_error(function, "tau must be greater than 0 but got %1%.", tau, pol); if (abs(z) == 0.0) return result; @@ -331,8 +330,7 @@ inline RealType jacobi_theta1_imp(RealType z, RealType q, const Policy& pol, const char *function) { BOOST_MATH_STD_USING if (q <= 0.0 || q >= 1.0) { - return policies::raise_domain_error(function, - "q must be greater than 0 and less than 1 but got %1%.", q, pol); + return policies::raise_domain_error(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol); } return jacobi_theta1tau_imp(z, RealType (-log(q)/constants::pi()), pol, function); } @@ -349,8 +347,7 @@ jacobi_theta2tau_imp(RealType z, RealType tau, const Policy& pol, const char *fu RealType q_n = 0, last_q_n, delta, result = 0; if (tau <= 0.0) { - return policies::raise_domain_error(function, - "tau must be greater than 0 but got %1%.", tau, pol); + return policies::raise_domain_error(function, "tau must be greater than 0 but got %1%.", tau, pol); } else if (tau < 1.0 && abs(z) == 0.0) { return jacobi_theta4tau(z, 1/tau, pol) / sqrt(tau); } else if (tau < 1.0) { // DLMF 20.7.31 @@ -383,8 +380,7 @@ inline RealType jacobi_theta2_imp(RealType z, RealType q, const Policy& pol, const char *function) { BOOST_MATH_STD_USING if (q <= 0.0 || q >= 1.0) { - return policies::raise_domain_error(function, - "q must be greater than 0 and less than 1 but got %1%.", q, pol); + return policies::raise_domain_error(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol); } return jacobi_theta2tau_imp(z, RealType (-log(q)/constants::pi()), pol, function); } @@ -425,8 +421,7 @@ jacobi_theta3tau_imp(RealType z, RealType tau, const Policy& pol, const char *fu { BOOST_MATH_STD_USING if (tau <= 0.0) { - return policies::raise_domain_error(function, - "tau must be greater than 0 but got %1%.", tau, pol); + return policies::raise_domain_error(function, "tau must be greater than 0 but got %1%.", tau, pol); } else if (tau < 1.0 && abs(z) == 0.0) { return jacobi_theta3tau(z, RealType(1/tau), pol) / sqrt(tau); } else if (tau < 1.0) { // DLMF 20.7.32 @@ -449,8 +444,7 @@ inline RealType jacobi_theta3m1_imp(RealType z, RealType q, const Policy& pol, const char *function) { BOOST_MATH_STD_USING if (q <= 0.0 || q >= 1.0) { - return policies::raise_domain_error(function, - "q must be greater than 0 and less than 1 but got %1%.", q, pol); + return policies::raise_domain_error(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol); } return jacobi_theta3m1tau_imp(z, RealType (-log(q)/constants::pi()), pol); } @@ -462,8 +456,7 @@ inline RealType jacobi_theta3_imp(RealType z, RealType q, const Policy& pol, const char *function) { BOOST_MATH_STD_USING if (q <= 0.0 || q >= 1.0) { - return policies::raise_domain_error(function, - "q must be greater than 0 and less than 1 but got %1%.", q, pol); + return policies::raise_domain_error(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol); } return jacobi_theta3tau_imp(z, RealType (-log(q)/constants::pi()), pol, function); } @@ -506,8 +499,7 @@ jacobi_theta4tau_imp(RealType z, RealType tau, const Policy& pol, const char *fu { BOOST_MATH_STD_USING if (tau <= 0.0) { - return policies::raise_domain_error(function, - "tau must be greater than 0 but got %1%.", tau, pol); + return policies::raise_domain_error(function, "tau must be greater than 0 but got %1%.", tau, pol); } else if (tau < 1.0 && abs(z) == 0.0) { return jacobi_theta2tau(z, 1/tau, pol) / sqrt(tau); } else if (tau < 1.0) { // DLMF 20.7.33 @@ -532,8 +524,7 @@ inline RealType jacobi_theta4m1_imp(RealType z, RealType q, const Policy& pol, const char *function) { BOOST_MATH_STD_USING if (q <= 0.0 || q >= 1.0) { - return policies::raise_domain_error(function, - "q must be greater than 0 and less than 1 but got %1%.", q, pol); + return policies::raise_domain_error(function, "q must be greater than 0 and less than 1 but got %1%.", q, pol); } return jacobi_theta4m1tau_imp(z, RealType (-log(q)/constants::pi()), pol); } @@ -545,8 +536,7 @@ inline RealType jacobi_theta4_imp(RealType z, RealType q, const Policy& pol, const char *function) { BOOST_MATH_STD_USING if (q <= 0.0 || q >= 1.0) { - return policies::raise_domain_error(function, - "|q| must be greater than zero and less than 1, but got %1%.", q, pol); + return policies::raise_domain_error(function, "|q| must be greater than zero and less than 1, but got %1%.", q, pol); } return jacobi_theta4tau_imp(z, RealType(-log(q)/constants::pi()), pol, function); } @@ -566,9 +556,7 @@ inline typename tools::promote_args::type jacobi_theta1tau(T z, U tau, con static const char* function = "boost::math::jacobi_theta1tau<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta1tau_imp(static_cast(z), static_cast(tau), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta1tau_imp(static_cast(z), static_cast(tau), forwarding_policy(), function), function); } template @@ -589,9 +577,7 @@ inline typename tools::promote_args::type jacobi_theta1(T z, U q, const Po static const char* function = "boost::math::jacobi_theta1<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta1_imp(static_cast(z), static_cast(q), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta1_imp(static_cast(z), static_cast(q), forwarding_policy(), function), function); } template @@ -612,9 +598,7 @@ inline typename tools::promote_args::type jacobi_theta2tau(T z, U tau, con static const char* function = "boost::math::jacobi_theta2tau<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta2tau_imp(static_cast(z), static_cast(tau), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta2tau_imp(static_cast(z), static_cast(tau), forwarding_policy(), function), function); } template @@ -635,9 +619,7 @@ inline typename tools::promote_args::type jacobi_theta2(T z, U q, const Po static const char* function = "boost::math::jacobi_theta2<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta2_imp(static_cast(z), static_cast(q), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta2_imp(static_cast(z), static_cast(q), forwarding_policy(), function), function); } template @@ -659,8 +641,7 @@ inline typename tools::promote_args::type jacobi_theta3m1tau(T z, U tau, c static const char* function = "boost::math::jacobi_theta3m1tau<%1%>(%1%)"; return policies::checked_narrowing_cast( - jacobi_theta3m1tau_imp(static_cast(z), static_cast(tau), - forwarding_policy()), function); + jacobi_theta3m1tau_imp(static_cast(z), static_cast(tau), forwarding_policy()), function); } template @@ -681,9 +662,7 @@ inline typename tools::promote_args::type jacobi_theta3tau(T z, U tau, con static const char* function = "boost::math::jacobi_theta3tau<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta3tau_imp(static_cast(z), static_cast(tau), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta3tau_imp(static_cast(z), static_cast(tau), forwarding_policy(), function), function); } template @@ -705,9 +684,7 @@ inline typename tools::promote_args::type jacobi_theta3m1(T z, U q, const static const char* function = "boost::math::jacobi_theta3m1<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta3m1_imp(static_cast(z), static_cast(q), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta3m1_imp(static_cast(z), static_cast(q), forwarding_policy(), function), function); } template @@ -728,9 +705,7 @@ inline typename tools::promote_args::type jacobi_theta3(T z, U q, const Po static const char* function = "boost::math::jacobi_theta3<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta3_imp(static_cast(z), static_cast(q), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta3_imp(static_cast(z), static_cast(q), forwarding_policy(), function), function); } template @@ -751,9 +726,7 @@ inline typename tools::promote_args::type jacobi_theta4m1tau(T z, U tau, c static const char* function = "boost::math::jacobi_theta4m1tau<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta4m1tau_imp(static_cast(z), static_cast(tau), - forwarding_policy()), function); + return policies::checked_narrowing_cast(jacobi_theta4m1tau_imp(static_cast(z), static_cast(tau), forwarding_policy()), function); } template @@ -774,9 +747,7 @@ inline typename tools::promote_args::type jacobi_theta4tau(T z, U tau, con static const char* function = "boost::math::jacobi_theta4tau<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta4tau_imp(static_cast(z), static_cast(tau), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta4tau_imp(static_cast(z), static_cast(tau), forwarding_policy(), function), function); } template @@ -797,9 +768,7 @@ inline typename tools::promote_args::type jacobi_theta4m1(T z, U q, const static const char* function = "boost::math::jacobi_theta4m1<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta4m1_imp(static_cast(z), static_cast(q), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta4m1_imp(static_cast(z), static_cast(q), forwarding_policy(), function), function); } template @@ -820,9 +789,7 @@ inline typename tools::promote_args::type jacobi_theta4(T z, U q, const Po static const char* function = "boost::math::jacobi_theta4<%1%>(%1%)"; - return policies::checked_narrowing_cast( - jacobi_theta4_imp(static_cast(z), static_cast(q), - forwarding_policy(), function), function); + return policies::checked_narrowing_cast(jacobi_theta4_imp(static_cast(z), static_cast(q), forwarding_policy(), function), function); } template diff --git a/include/boost/math/special_functions/lambert_w.hpp b/include/boost/math/special_functions/lambert_w.hpp index 1d21973e40..671432c679 100644 --- a/include/boost/math/special_functions/lambert_w.hpp +++ b/include/boost/math/special_functions/lambert_w.hpp @@ -70,14 +70,12 @@ BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES_ITERATIONS // Show evaluation of #include #include -#include -#include #include #include // Needed for testing and diagnostics only. -#include -#include +//#include +//#include #include // For float_distance. using lookup_t = double; // Type for lookup table (double or float, or even long double?) @@ -401,56 +399,14 @@ T lambert_w_singularity_series(const T p) if (absp < T(0.01159)) { // Only 6 near-singularity series terms are useful. - return - -1 + - p * (1 + - p * (q[2] + - p * (q[3] + - p * (q[4] + - p * (q[5] + - p * q[6] - ))))); + return -1 + p * (1 + p * (q[2] + p * (q[3] + p * (q[4] + p * (q[5] + p * q[6]))))); } else if (absp < T(0.0766)) // Use 10 near-singularity series terms. { // Use 10 near-singularity series terms. - return - -1 + - p * (1 + - p * (q[2] + - p * (q[3] + - p * (q[4] + - p * (q[5] + - p * (q[6] + - p * (q[7] + - p * (q[8] + - p * (q[9] + - p * q[10] - ))))))))); + return -1 + p * (1 + p * (q[2] + p * (q[3] + p * (q[4] + p * (q[5] + p * (q[6] + p * (q[7] + p * (q[8] + p * (q[9] + p * q[10]))))))))); } // Use all 20 near-singularity series terms. - return - -1 + - p * (1 + - p * (q[2] + - p * (q[3] + - p * (q[4] + - p * (q[5] + - p * (q[6] + - p * (q[7] + - p * (q[8] + - p * (q[9] + - p * (q[10] + - p * (q[11] + - p * (q[12] + - p * (q[13] + - p * (q[14] + - p * (q[15] + - p * (q[16] + - p * (q[17] + - p * (q[18] + - p * (q[19] + - p * q[20] // Last Fukushima term. - ))))))))))))))))))); + return -1 + p * (1 + p * (q[2] + p * (q[3] + p * (q[4] + p * (q[5] + p * (q[6] + p * (q[7] + p * (q[8] + p * (q[9] + p * (q[10] + p * (q[11] + p * (q[12] + p * (q[13] + p * (q[14] + p * (q[15] + p * (q[16] + p * (q[17] + p * (q[18] + p * (q[19] + p * q[20] /* Last Fukushima term.*/))))))))))))))))))); // + // more terms for more precise T: long double ... //// but makes almost no difference, so don't use more terms? // p*q[21] + @@ -808,7 +764,7 @@ T lambert_w0_small_z(const T z, const Policy&, std::integral_constant co #else template -inline T lambert_w0_small_z(const T z, const Policy& pol, std::integral_constant const&) +inline T lambert_w0_small_z(const T z, const Policy& pol, std::integral_constant const&) // LCOV_EXCL_LINE body is covered, strangley this line is not. { return lambert_w0_small_z(z, pol, std::integral_constant()); } @@ -931,7 +887,7 @@ inline T lambert_w0_small_z(T z, const Policy& pol, std::integral_constant::max_digits10); - T result = evaluate_polynomial(coeff, z); + T result = evaluate_polynomial(coeff, z); // LCOV_EXCL_LINE next line covered but not this one strangely - GCOV SNAFU? // template // V evaluate_polynomial(const T(&poly)[N], const V& val); // Size of coeff found from N @@ -1049,6 +1005,7 @@ T lambert_w_positive_rational_float(T z) // Maximum Deviation Found: 2.993e-08 // Expected Error Term : 2.993e-08 // Maximum Relative Change in Control Points : 7.555e-04 Y offset : -8.196592331e-01 + // LCOV_EXCL_START static const T Y = 8.196592331e-01f; static const T P[] = { 1.803388345e-01f, @@ -1061,11 +1018,13 @@ T lambert_w_positive_rational_float(T z) 2.871703469e+00f, 1.690949264e+00f, }; + // LCOV_EXCL_STOP return z * (Y + boost::math::tools::evaluate_polynomial(P, z) / boost::math::tools::evaluate_polynomial(Q, z)); } else { // 0.5 < z < 2 // Max error in interpolated form: 1.018e-08 + // LCOV_EXCL_START static const T Y = 5.503368378e-01f; static const T P[] = { 4.493332766e-01f, @@ -1079,6 +1038,7 @@ T lambert_w_positive_rational_float(T z) 1.830840318e+00f, 2.407221031e-01f, }; + // LCOV_EXCL_STOP return z * (Y + boost::math::tools::evaluate_rational(P, Q, z)); } } @@ -1086,6 +1046,7 @@ T lambert_w_positive_rational_float(T z) { // 2 < z < 6 // Max error in interpolated form: 2.944e-08 + // LCOV_EXCL_START static const T Y = 1.162393570e+00f; static const T P[] = { -1.144183394e+00f, @@ -1099,12 +1060,14 @@ T lambert_w_positive_rational_float(T z) 2.295580708e-01f, 5.477869455e-03f, }; + // LCOV_EXCL_STOP return Y + boost::math::tools::evaluate_rational(P, Q, z); } else if (z < 18) { // 6 < z < 18 // Max error in interpolated form: 5.893e-08 + // LCOV_EXCL_START static const T Y = 1.809371948e+00f; static const T P[] = { -1.689291769e+00f, @@ -1118,11 +1081,13 @@ T lambert_w_positive_rational_float(T z) 4.489521292e-02f, 4.076716763e-04f, }; + // LCOV_EXCL_STOP return Y + boost::math::tools::evaluate_rational(P, Q, z); } else if (z < T(9897.12905874)) // 2.8 < log(z) < 9.2 { // Max error in interpolated form: 1.771e-08 + // LCOV_EXCL_START static const T Y = -1.402973175e+00f; static const T P[] = { 1.966174312e+00f, @@ -1137,12 +1102,14 @@ T lambert_w_positive_rational_float(T z) 3.397187918e-03f, -1.321489743e-05f, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_polynomial(P, log_w) / boost::math::tools::evaluate_polynomial(Q, log_w); } else if (z < T(7.896296e+13)) // 9.2 < log(z) <= 32 { // Max error in interpolated form: 5.821e-08 + // LCOV_EXCL_START static const T Y = -2.735729218e+00f; static const T P[] = { 3.424903470e+00f, @@ -1157,11 +1124,13 @@ T lambert_w_positive_rational_float(T z) -1.357889535e-05f, 7.312865624e-08f, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_polynomial(P, log_w) / boost::math::tools::evaluate_polynomial(Q, log_w); } // Max error in interpolated form: 1.491e-08 + // LCOV_EXCL_START static const T Y = -4.012863159e+00f; static const T P[] = { 4.431629226e+00f, @@ -1176,6 +1145,7 @@ T lambert_w_positive_rational_float(T z) 1.609659944e-05f, -5.111523436e-09f, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_polynomial(P, log_w) / boost::math::tools::evaluate_polynomial(Q, log_w); @@ -1191,6 +1161,7 @@ T lambert_w_negative_rational_float(T z, const Policy& pol) { // -0.27 < z < -0.051 // Max error in interpolated form: 5.080e-08 + // LCOV_EXCL_START static const T Y = 1.255809784e+00f; static const T P[] = { -2.558083412e-01f, @@ -1204,6 +1175,7 @@ T lambert_w_negative_rational_float(T z, const Policy& pol) 7.914062868e+00f, 3.501498501e+00f, }; + // LCOV_EXCL_STOP return z * (Y + boost::math::tools::evaluate_rational(P, Q, z)); } else @@ -1215,6 +1187,7 @@ T lambert_w_negative_rational_float(T z, const Policy& pol) else if (z > T(-0.3578794411714423215955237701)) { // Very close to branch singularity. // Max error in interpolated form: 5.269e-08 + // LCOV_EXCL_START static const T Y = 1.220928431e-01f; static const T P[] = { -1.221787446e-01f, @@ -1229,6 +1202,7 @@ T lambert_w_negative_rational_float(T z, const Policy& pol) -1.361804274e+03f, 1.117826726e+03f, }; + // LCOV_EXCL_STOP T d = z + 0.367879441171442321595523770161460867445811f; return -d / (Y + boost::math::tools::evaluate_polynomial(P, d) / boost::math::tools::evaluate_polynomial(Q, d)); } @@ -1276,6 +1250,7 @@ T lambert_w_positive_rational_double(T z) if (z < 0.5) { // Max error in interpolated form: 2.255e-17 + // LCOV_EXCL_START static const T offset = 8.19659233093261719e-01; static const T P[] = { 1.80340766906685177e-01, @@ -1295,11 +1270,13 @@ T lambert_w_positive_rational_double(T z) 4.03760534788374589e+00, 2.91327346750475362e-01 }; + // LCOV_EXCL_STOP return z * (offset + boost::math::tools::evaluate_polynomial(P, z) / boost::math::tools::evaluate_polynomial(Q, z)); } else { // Max error in interpolated form: 3.806e-18 + // LCOV_EXCL_START static const T offset = 5.50335884094238281e-01; static const T P[] = { 4.49664083944098322e-01, @@ -1320,7 +1297,7 @@ T lambert_w_positive_rational_double(T z) 2.29040824649748117e+00, 2.21610620995418981e-01, 5.70597669908194213e-03 - }; + };// LCOV_EXCL_STOP return z * (offset + boost::math::tools::evaluate_rational(P, Q, z)); } } @@ -1328,6 +1305,7 @@ T lambert_w_positive_rational_double(T z) { // 2 < z < 6 // Max error in interpolated form: 1.216e-17 + // LCOV_EXCL_START static const T Y = 1.16239356994628906e+00; static const T P[] = { -1.16230494982099475e+00, @@ -1349,12 +1327,14 @@ T lambert_w_positive_rational_double(T z) 9.25176499518388571e-04, 4.43611344705509378e-06, }; + // LCOV_EXCL_STOP return Y + boost::math::tools::evaluate_rational(P, Q, z); } else if (z < 18) { // 6 < z < 18 // Max error in interpolated form: 1.985e-19 + // LCOV_EXCL_START static const T offset = 1.80937194824218750e+00; static const T P[] = { @@ -1379,11 +1359,13 @@ T lambert_w_positive_rational_double(T z) 6.05713225608426678e-07, 8.17517283816615732e-10 }; + // LCOV_EXCL_STOP return offset + boost::math::tools::evaluate_rational(P, Q, z); } else if (z < 9897.12905874) // 2.8 < log(z) < 9.2 { // Max error in interpolated form: 1.195e-18 + // LCOV_EXCL_START static const T Y = -1.40297317504882812e+00; static const T P[] = { 1.97011826279311924e+00, @@ -1407,12 +1389,14 @@ T lambert_w_positive_rational_double(T z) 1.36363515125489502e-06, 3.44200749053237945e-09, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w); } else if (z < 7.896296e+13) // 9.2 < log(z) <= 32 { // Max error in interpolated form: 6.529e-18 + // LCOV_EXCL_START static const T Y = -2.73572921752929688e+00; static const T P[] = { 3.30547638424076217e+00, @@ -1436,12 +1420,14 @@ T lambert_w_positive_rational_double(T z) 4.97253225968548872e-09, 3.39460723731970550e-12, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w); } else if (z < 2.6881171e+43) // 32 < log(z) < 100 { // Max error in interpolated form: 2.015e-18 + // LCOV_EXCL_START static const T Y = -4.01286315917968750e+00; static const T P[] = { 5.07714858354309672e+00, @@ -1465,12 +1451,14 @@ T lambert_w_positive_rational_double(T z) -9.35271498075378319e-11, -2.60648331090076845e-14, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w); } else // 100 < log(z) < 710 { // Max error in interpolated form: 5.277e-18 + // LCOV_EXCL_START static const T Y = -5.70115661621093750e+00; static const T P[] = { 6.42275660145116698e+00, @@ -1498,6 +1486,7 @@ T lambert_w_positive_rational_double(T z) 1.11775518708172009e-20, 3.78250395617836059e-25, }; + // LCOV_EXCL_STOP T log_w = log(z); return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w); } @@ -1515,6 +1504,7 @@ T lambert_w_negative_rational_double(T z, const Policy& pol) // Maximum Deviation Found: 4.402e-22 // Expected Error Term : 4.240e-22 // Maximum Relative Change in Control Points : 4.115e-03 + // LCOV_EXCL_START static const T Y = 1.08633995056152344e+00; static const T P[] = { -8.63399505615014331e-02, @@ -1532,6 +1522,7 @@ T lambert_w_negative_rational_double(T z, const Policy& pol) 1.31256080849023319e+01, 2.11640324843601588e+00, }; + // LCOV_EXCL_STOP return z * (Y + boost::math::tools::evaluate_rational(P, Q, z)); } else @@ -1546,6 +1537,7 @@ T lambert_w_negative_rational_double(T z, const Policy& pol) // Maximum Deviation Found: 2.898e-20 // Expected Error Term : 2.873e-20 // Maximum Relative Change in Control Points : 3.779e-04 + // LCOV_EXCL_START static const T Y = 1.20359611511230469e+00; static const T P[] = { -2.03596115108465635e-01, @@ -1565,11 +1557,13 @@ T lambert_w_negative_rational_double(T z, const Policy& pol) 2.82060127225153607e+01, 4.10677610657724330e+00, }; + // LCOV_EXCL_STOP return z * (Y + boost::math::tools::evaluate_rational(P, Q, z)); } else if (z > -0.3178794411714423215955237) { // Max error in interpolated form: 6.996e-18 + // LCOV_EXCL_START static const T Y = 3.49680423736572266e-01; static const T P[] = { -3.49729841718749014e-01, @@ -1592,12 +1586,14 @@ T lambert_w_negative_rational_double(T z, const Policy& pol) -5.61719645211570871e+05, 6.27765369292636844e+04, }; + // LCOV_EXCL_STOP T d = z + 0.367879441171442321595523770161460867445811; return -d / (Y + boost::math::tools::evaluate_polynomial(P, d) / boost::math::tools::evaluate_polynomial(Q, d)); } else if (z > -0.3578794411714423215955237701) { // Max error in interpolated form: 1.404e-17 + // LCOV_EXCL_START static const T Y = 5.00126481056213379e-02; static const T P[] = { -5.00173570682372162e-02, @@ -1621,6 +1617,7 @@ T lambert_w_negative_rational_double(T z, const Policy& pol) -4.59414247951143131e+10, -1.72845216404874299e+10, }; + // LCOV_EXCL_STOP T d = z + 0.36787944117144232159552377016146086744581113103176804; return -d / (Y + boost::math::tools::evaluate_polynomial(P, d) / boost::math::tools::evaluate_polynomial(Q, d)); } @@ -1775,52 +1772,29 @@ T lambert_wm1_imp(const T z, const Policy& pol) // Check for edge and corner cases first: if ((boost::math::isnan)(z)) { - return policies::raise_domain_error(function, - "Argument z is NaN!", - z, pol); + return policies::raise_domain_error(function, "Argument z is NaN!", z, pol); } // isnan if ((boost::math::isinf)(z)) { - return policies::raise_domain_error(function, - "Argument z is infinite!", - z, pol); + return policies::raise_domain_error(function, "Argument z is infinite!", z, pol); } // isinf if (z == static_cast(0)) { // z is exactly zero so return -std::numeric_limits::infinity(); - if (std::numeric_limits::has_infinity) - { - return -std::numeric_limits::infinity(); - } - else - { - return -tools::max_value(); - } + return -policies::raise_overflow_error(function, nullptr, z, pol); } if (boost::math::detail::has_denorm_now()) { // All real types except arbitrary precision. if (!(boost::math::isnormal)(z)) { // Almost zero - might also just return infinity like z == 0 or max_value? - return policies::raise_overflow_error(function, - "Argument z = %1% is denormalized! (must be z > (std::numeric_limits::min)() or z == 0)", - z, pol); + return -policies::raise_overflow_error(function, "Argument z = %1% is denormalized! (must be z > (std::numeric_limits::min)() or z == 0)", z, pol); } } if (z > static_cast(0)) { // - return policies::raise_domain_error(function, - "Argument z = %1% is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?)", - z, pol); - } - if (z > -boost::math::tools::min_value()) - { // z is denormalized, so cannot be computed. - // -std::numeric_limits::min() is smallest for type T, - // for example, for double: lambert_wm1(-2.2250738585072014e-308) = -714.96865723796634 - return policies::raise_overflow_error(function, - "Argument z = %1% is too small (z < -std::numeric_limits::min so denormalized) for Lambert W-1 branch!", - z, pol); + return policies::raise_domain_error(function, "Argument z = %1% is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?)", z, pol); } if (z == -boost::math::constants::exp_minus_one()) // == singularity/branch point z = -exp(-1) = -0.36787944. { // At singularity, so return exactly -1. @@ -1829,35 +1803,28 @@ T lambert_wm1_imp(const T z, const Policy& pol) // z is too negative for the W-1 (or W0) branch. if (z < -boost::math::constants::exp_minus_one()) // > singularity/branch point z = -exp(-1) = -0.36787944. { - return policies::raise_domain_error(function, - "Argument z = %1% is out of range (z < -exp(-1) = -3.6787944... <= 0) for Lambert W-1 (or W0) branch!", - z, pol); + return policies::raise_domain_error(function, "Argument z = %1% is out of range (require -exp(-1) = -0.36787944... < z <= 0) for Lambert W-1 (or W0) branch!", z, pol); } if (z < static_cast(-0.35)) { // Close to singularity/branch point z = -0.3678794411714423215955237701614608727 but on W-1 branch. const T p2 = 2 * (boost::math::constants::e() * z + 1); - if (p2 == 0) - { // At the singularity at branch point. - return -1; - } - if (p2 > 0) - { - T w_series = lambert_w_singularity_series(T(-sqrt(p2))); - if (boost::math::tools::digits() > 53) - { // Multiprecision, so try a Halley refinement. - w_series = lambert_w_detail::lambert_w_halley_iterate(w_series, z); + // Commented out, requires z = -1 / 2e which is greater than -0.35 so this whole branch is not taken. + //if (p2 == 0) + //{ // At the singularity at branch point. + // return -1; + // } + BOOST_MATH_ASSERT(p2 > 0); + T w_series = lambert_w_singularity_series(T(-sqrt(p2))); + if (boost::math::tools::digits() > 53) + { // Multiprecision, so try a Halley refinement. + w_series = lambert_w_detail::lambert_w_halley_iterate(w_series, z); #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_WM1_NOT_BUILTIN - std::streamsize saved_precision = std::cout.precision(std::numeric_limits::max_digits10); - std::cout << "Lambert W-1 Halley updated to " << w_series << std::endl; - std::cout.precision(saved_precision); + std::streamsize saved_precision = std::cout.precision(std::numeric_limits::max_digits10); + std::cout << "Lambert W-1 Halley updated to " << w_series << std::endl; + std::cout.precision(saved_precision); #endif // BOOST_MATH_INSTRUMENT_LAMBERT_WM1_NOT_BUILTIN - } - return w_series; } - // Should not get here. - return policies::raise_domain_error(function, - "Argument z = %1% is out of range for Lambert W-1 branch. (Should not get here - please report!)", - z, pol); + return w_series; } // if (z < -0.35) using lambert_w_lookup::wm1es; @@ -1908,7 +1875,7 @@ T lambert_wm1_imp(const T z, const Policy& pol) #endif // BOOST_MATH_INSTRUMENT_LAMBERT_WM1_TINY if (policies::digits() < 12) { // For the worst case near w = 64, the error in the 'guess' is ~0.008, ratio ~ 0.0001 or 1 in 10,000 digits 10 ~= 4, or digits2 ~= 12. - return guess; + return guess; // LCOV_EXCL_LINE We don't have a test type with few enough digits to trigger this. } T result = lambert_w_detail::lambert_w_halley_iterate(guess, z); return result; @@ -1967,9 +1934,7 @@ T lambert_wm1_imp(const T z, const Policy& pol) } // else z < g[63] == -1.0264389699511303e-26, so Lambert W-1 integer part > 64. // This should not now occur (should be caught by test and code above) so should be a logic_error? - return policies::raise_domain_error(function, - "Argument z = %1% is too small (< -1.026439e-26) (logic error - please report!)", - z, pol); + return policies::raise_evaluation_error(function, "Argument z = %1% is too small (< -1.026439e-26) (logic error - please report!)", z, pol); // LCOV_EXCL_LINE overshot: { int nh = n / 2; @@ -2127,34 +2092,44 @@ T lambert_wm1_imp(const T z, const Policy& pol) return lambert_w_detail::lambert_wm1_imp(result_type(z), policies::policy<>()); } // lambert_wm1(T z) + // First derivative of Lambert W0 and W-1. + namespace lambert_w_detail { + template + inline typename tools::promote_args::type + lambert_w0_prime(T z, const Policy& pol) + { + using result_type = typename tools::promote_args::type; + using std::numeric_limits; + if (z == 0) + { + return static_cast(1); + } + // This is the sensible choice if we regard the Lambert-W function as complex analytic. + // Of course on the real line, it's just undefined. + if (z == -boost::math::constants::exp_minus_one()) + { + return boost::math::policies::raise_overflow_error("lambert_w0_prime", nullptr, z, pol); + } + // if z < -1/e, we'll let lambert_w0 do the error handling: + result_type w = lambert_w0(result_type(z), pol); + // If w ~ -1, then presumably this can get inaccurate. + // Is there an accurate way to evaluate 1 + W(-1/e + eps)? + // Yes: This is discussed in the Princeton Companion to Applied Mathematics, + // 'The Lambert-W function', Section 1.3: Series and Generating Functions. + // 1 + W(-1/e + x) ~ sqrt(2ex). + // Nick is not convinced this formula is more accurate than the naive one. + // However, for z != -1/e, we never get rounded to w = -1 in any precision I've tested (up to cpp_bin_float_100). + return w / (z * (1 + w)); + } // lambert_w0_prime(T z) + } // First derivative of Lambert W0 and W-1. template inline typename tools::promote_args::type - lambert_w0_prime(T z, const Policy& pol) + lambert_w0_prime(T z, const Policy& pol) { - using result_type = typename tools::promote_args::type; - using std::numeric_limits; - if (z == 0) - { - return static_cast(1); - } - // This is the sensible choice if we regard the Lambert-W function as complex analytic. - // Of course on the real line, it's just undefined. - if (z == - boost::math::constants::exp_minus_one()) - { - return numeric_limits::has_infinity ? numeric_limits::infinity() : boost::math::tools::max_value(); - } - // if z < -1/e, we'll let lambert_w0 do the error handling: - result_type w = lambert_w0(result_type(z), pol); - // If w ~ -1, then presumably this can get inaccurate. - // Is there an accurate way to evaluate 1 + W(-1/e + eps)? - // Yes: This is discussed in the Princeton Companion to Applied Mathematics, - // 'The Lambert-W function', Section 1.3: Series and Generating Functions. - // 1 + W(-1/e + x) ~ sqrt(2ex). - // Nick is not convinced this formula is more accurate than the naive one. - // However, for z != -1/e, we never get rounded to w = -1 in any precision I've tested (up to cpp_bin_float_100). - return w / (z * (1 + w)); - } // lambert_w0_prime(T z) + using result_type = typename tools::promote_args::type; + return lambert_w_detail::lambert_w0_prime(static_cast(z), pol); + } template inline typename tools::promote_args::type @@ -2176,7 +2151,7 @@ T lambert_wm1_imp(const T z, const Policy& pol) //if (z == - boost::math::constants::exp_minus_one()) if (z == 0 || z == - boost::math::constants::exp_minus_one()) { - return numeric_limits::has_infinity ? -numeric_limits::infinity() : -boost::math::tools::max_value(); + return -boost::math::policies::raise_overflow_error("lambert_wm1_prime", nullptr, z, pol); } result_type w = lambert_wm1(z, pol); diff --git a/include/boost/math/special_functions/legendre.hpp b/include/boost/math/special_functions/legendre.hpp index 5e7f0029a6..992953e231 100644 --- a/include/boost/math/special_functions/legendre.hpp +++ b/include/boost/math/special_functions/legendre.hpp @@ -40,10 +40,7 @@ T legendre_imp(unsigned l, T x, const Policy& pol, bool second = false) static const char* function = "boost::math::legrendre_p<%1%>(unsigned, %1%)"; // Error handling: if((x < -1) || (x > 1)) - return policies::raise_domain_error( - function, - "The Legendre Polynomial is defined for" - " -1 <= x <= 1, but got x = %1%.", x, pol); + return policies::raise_domain_error(function, "The Legendre Polynomial is defined for -1 <= x <= 1, but got x = %1%.", x, pol); T p0, p1; if(second) @@ -84,17 +81,11 @@ T legendre_p_prime_imp(unsigned l, T x, const Policy& pol, T* Pn static const char* function = "boost::math::legrendre_p_prime<%1%>(unsigned, %1%)"; // Error handling: if ((x < -1) || (x > 1)) - return policies::raise_domain_error( - function, - "The Legendre Polynomial is defined for" - " -1 <= x <= 1, but got x = %1%.", x, pol); + return policies::raise_domain_error(function, "The Legendre Polynomial is defined for -1 <= x <= 1, but got x = %1%.", x, pol); if (l == 0) { - if (Pn) - { - *Pn = 1; - } + BOOST_MATH_ASSERT(Pn == nullptr); // There are no zeros of P_0 so we shoud never call this with l = 0 and Pn non-null. return 0; } T p0 = 1; @@ -218,7 +209,7 @@ std::vector legendre_p_zeros_imp(int n, const Policy& pol) ++k; } return zeros; -} +} // LCOV_EXCL_LINE } // namespace detail @@ -310,10 +301,7 @@ T legendre_p_imp(int l, int m, T x, T sin_theta_power, const Policy& pol) BOOST_MATH_STD_USING // Error handling: if((x < -1) || (x > 1)) - return policies::raise_domain_error( - "boost::math::legendre_p<%1%>(int, int, %1%)", - "The associated Legendre Polynomial is defined for" - " -1 <= x <= 1, but got x = %1%.", x, pol); + return policies::raise_domain_error("boost::math::legendre_p<%1%>(int, int, %1%)", "The associated Legendre Polynomial is defined for -1 <= x <= 1, but got x = %1%.", x, pol); // Handle negative arguments first: if(l < 0) return legendre_p_imp(-l-1, m, x, sin_theta_power, pol); diff --git a/include/boost/math/special_functions/log1p.hpp b/include/boost/math/special_functions/log1p.hpp index 67e8c14222..6fb26bf6af 100644 --- a/include/boost/math/special_functions/log1p.hpp +++ b/include/boost/math/special_functions/log1p.hpp @@ -96,11 +96,9 @@ BOOST_MATH_GPU_ENABLED T log1p_imp(T const & x, const Policy& pol, const boost:: constexpr auto function = "boost::math::log1p<%1%>(%1%)"; if((x < -1) || (boost::math::isnan)(x)) - return policies::raise_domain_error( - function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error(function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - function, nullptr, pol); + return -policies::raise_overflow_error(function, nullptr, pol); result_type a = abs(result_type(x)); if(a > result_type(0.5f)) @@ -126,11 +124,9 @@ BOOST_MATH_GPU_ENABLED T log1p_imp(T const& x, const Policy& pol, const boost::m constexpr auto function = "boost::math::log1p<%1%>(%1%)"; if(x < -1) - return policies::raise_domain_error( - function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error(function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - function, nullptr, pol); + return -policies::raise_overflow_error(function, nullptr, pol); T a = fabs(x); if(a > 0.5f) @@ -179,11 +175,9 @@ BOOST_MATH_GPU_ENABLED T log1p_imp(T const& x, const Policy& pol, const boost::m constexpr auto function = "boost::math::log1p<%1%>(%1%)"; if(x < -1) - return policies::raise_domain_error( - function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error(function, "log1p(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - function, nullptr, pol); + return -policies::raise_overflow_error(function, nullptr, pol); T a = fabs(x); if(a > 0.5f) @@ -301,11 +295,9 @@ template BOOST_MATH_GPU_ENABLED inline float log1p(float x, const Policy& pol) { if(x < -1) - return policies::raise_domain_error( - "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error("log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - "log1p<%1%>(%1%)", nullptr, pol); + return -policies::raise_overflow_error("log1p<%1%>(%1%)", nullptr, pol); return std::log1p(x); } #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS @@ -313,11 +305,9 @@ template BOOST_MATH_GPU_ENABLED inline long double log1p(long double x, const Policy& pol) { if(x < -1) - return policies::raise_domain_error( - "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error("log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - "log1p<%1%>(%1%)", nullptr, pol); + return -policies::raise_overflow_error("log1p<%1%>(%1%)", nullptr, pol); return std::log1p(x); } #endif @@ -325,11 +315,9 @@ template BOOST_MATH_GPU_ENABLED inline double log1p(double x, const Policy& pol) { if(x < -1) - return policies::raise_domain_error( - "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error("log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - "log1p<%1%>(%1%)", nullptr, pol); + return -policies::raise_overflow_error("log1p<%1%>(%1%)", nullptr, pol); return std::log1p(x); } @@ -350,11 +338,9 @@ BOOST_MATH_GPU_ENABLED inline typename tools::promote_args::type constexpr auto function = "boost::math::log1pmx<%1%>(%1%)"; if(x < -1) - return policies::raise_domain_error( - function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol); + return policies::raise_domain_error(function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol); if(x == -1) - return -policies::raise_overflow_error( - function, nullptr, pol); + return -policies::raise_overflow_error(function, nullptr, pol); result_type a = abs(result_type(x)); if(a > result_type(0.95f)) diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 2129f0898e..74c34f06ad 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -469,13 +469,9 @@ T float_distance_imp(const T& a, const T& b, const std::true_type&, const Policy // static const char* function = "float_distance<%1%>(%1%, %1%)"; if(!(boost::math::isfinite)(a)) - return policies::raise_domain_error( - function, - "Argument a must be finite, but got %1%", a, pol); + return policies::raise_domain_error(function, "Argument a must be finite, but got %1%", a, pol); if(!(boost::math::isfinite)(b)) - return policies::raise_domain_error( - function, - "Argument b must be finite, but got %1%", b, pol); + return policies::raise_domain_error(function, "Argument b must be finite, but got %1%", b, pol); // // Special cases: // @@ -577,13 +573,9 @@ T float_distance_imp(const T& a, const T& b, const std::false_type&, const Polic // static const char* function = "float_distance<%1%>(%1%, %1%)"; if(!(boost::math::isfinite)(a)) - return policies::raise_domain_error( - function, - "Argument a must be finite, but got %1%", a, pol); + return policies::raise_domain_error(function, "Argument a must be finite, but got %1%", a, pol); if(!(boost::math::isfinite)(b)) - return policies::raise_domain_error( - function, - "Argument b must be finite, but got %1%", b, pol); + return policies::raise_domain_error(function, "Argument b must be finite, but got %1%", b, pol); // // Special cases: // @@ -726,9 +718,7 @@ T float_advance_imp(T val, int distance, const std::true_type&, const Policy& po int fpclass = (boost::math::fpclassify)(val); if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE)) - return policies::raise_domain_error( - function, - "Argument val must be finite, but got %1%", val, pol); + return policies::raise_domain_error(function, "Argument val must be finite, but got %1%", val, pol); if(val < 0) return -float_advance(-val, -distance, pol); @@ -760,10 +750,8 @@ T float_advance_imp(T val, int distance, const std::true_type&, const Policy& po int expon; (void)frexp(val, &expon); T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon); - if(val <= tools::min_value()) - { - limit = sign(T(distance)) * tools::min_value(); - } + // We can not have denorms here, since we have taken care of them above: + BOOST_MATH_ASSERT(val > tools::min_value()); T limit_distance = float_distance(val, limit); while(fabs(limit_distance) < abs(distance)) { @@ -782,7 +770,7 @@ T float_advance_imp(T val, int distance, const std::true_type&, const Policy& po limit_distance = float_distance(val, limit); if(distance && (limit_distance == 0)) { - return policies::raise_evaluation_error(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol); + return policies::raise_evaluation_error(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol); // LCOV_EXCL_LINE This *should* be unreachable. } } if((0.5f == frexp(val, &expon)) && (distance < 0)) @@ -791,7 +779,7 @@ T float_advance_imp(T val, int distance, const std::true_type&, const Policy& po if(val != 0) diff = distance * ldexp(T(1), expon - tools::digits()); if(diff == 0) - diff = distance * detail::get_smallest_value(); + diff = distance * detail::get_smallest_value(); // LCOV_EXCL_LINE This *should* be unreachable given that denorms are handled above already. return val += diff; } // float_advance_imp // @@ -812,9 +800,7 @@ T float_advance_imp(T val, int distance, const std::false_type&, const Policy& p int fpclass = (boost::math::fpclassify)(val); if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE)) - return policies::raise_domain_error( - function, - "Argument val must be finite, but got %1%", val, pol); + return policies::raise_domain_error(function, "Argument val must be finite, but got %1%", val, pol); if(val < 0) return -float_advance(-val, -distance, pol); @@ -845,10 +831,7 @@ T float_advance_imp(T val, int distance, const std::false_type&, const Policy& p std::intmax_t expon = 1 + ilogb(val); T limit = scalbn(T(1), distance < 0 ? expon - 1 : expon); - if(val <= tools::min_value()) - { - limit = sign(T(distance)) * tools::min_value(); - } + BOOST_MATH_ASSERT(val > tools::min_value()); // denorms already handled. T limit_distance = float_distance(val, limit); while(fabs(limit_distance) < abs(distance)) { @@ -861,13 +844,13 @@ T float_advance_imp(T val, int distance, const std::false_type&, const Policy& p } else { - limit *= std::numeric_limits::radix; - expon++; + limit *= std::numeric_limits::radix; // LCOV_EXCL_LINE Probably unreachable for the decimal types we have? + expon++; // LCOV_EXCL_LINE } limit_distance = float_distance(val, limit); if(distance && (limit_distance == 0)) { - return policies::raise_evaluation_error(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol); + return policies::raise_evaluation_error(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol); // LCOV_EXCL_LINE should never get here! } } /*expon = 1 + ilogb(val); @@ -877,7 +860,7 @@ T float_advance_imp(T val, int distance, const std::false_type&, const Policy& p if(val != 0) diff = distance * scalbn(T(1), expon - std::numeric_limits::digits); if(diff == 0) - diff = distance * detail::get_smallest_value(); + diff = distance * detail::get_smallest_value(); // LCOV_EXCL_LINE This *should* be unreachable given that denorms are handled above. return val += diff; } // float_advance_imp diff --git a/include/boost/math/special_functions/nonfinite_num_facets.hpp b/include/boost/math/special_functions/nonfinite_num_facets.hpp index 697a35f983..5e08c10d3f 100644 --- a/include/boost/math/special_functions/nonfinite_num_facets.hpp +++ b/include/boost/math/special_functions/nonfinite_num_facets.hpp @@ -493,10 +493,10 @@ namespace boost { return; } } - break; + break; // LCOV_EXCL_LINE simple fallthrough not registered as covered. default: - break; + break; // LCOV_EXCL_LINE simple fallthrough not registered as covered. } state |= std::ios_base::failbit; @@ -523,7 +523,7 @@ namespace boost { val = std::numeric_limits::infinity(); return; } - break; + break; // LCOV_EXCL_LINE simple fallthrough not registered as covered. case 'd': // 1.#IND" if(std::numeric_limits::has_quiet_NaN @@ -533,10 +533,10 @@ namespace boost { val = positive_nan(); return; } - break; + break; // LCOV_EXCL_LINE simple fallthrough not registered as covered. - default: - break; + default: // LCOV_EXCL_LINE simple fallthrough not registered as covered. + break; // LCOV_EXCL_LINE simple fallthrough not registered as covered. } } diff --git a/include/boost/math/special_functions/owens_t.hpp b/include/boost/math/special_functions/owens_t.hpp index f732e8b6d8..4fa5c6aa7e 100644 --- a/include/boost/math/special_functions/owens_t.hpp +++ b/include/boost/math/special_functions/owens_t.hpp @@ -120,6 +120,7 @@ namespace boost } // for(unsigned short i = 0; i != 7; i++) // interpret select array as 8x15 matrix + BOOST_MATH_ASSERT(iaint * 15 + ihint < (int)(sizeof(select) / sizeof(select[0]))); return select[iaint*15 + ihint]; } // unsigned short owens_t_compute_code(const RealType h, const RealType a) @@ -810,14 +811,13 @@ namespace boost { return owens_t_znorm2(RealType(-h), pol) * owens_t_znorm2(h, pol) / 2; } - if(a >= tools::max_value()) - { - return owens_t_znorm2(RealType(fabs(h)), pol); - } + // Rationale: when a>1 we call this routine with 1/a: + BOOST_MATH_ASSERT(a <= 1); RealType val = 0; // avoid compiler warnings, 0 will be overwritten in any case const unsigned short icode = owens_t_compute_code(h, a); const unsigned short m = owens_t_get_order(icode, val /* just a dummy for the type */, pol); static const unsigned short meth[] = {1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 6}; // 18 entries + BOOST_MATH_ASSERT(icode < sizeof(meth) / sizeof(meth[0])); // determine the appropriate method, T1 ... T6 switch( meth[icode] ) @@ -842,8 +842,6 @@ namespace boost case 6: // T6 val = owens_t_T6(h,a, pol); break; - default: - val = policies::raise_evaluation_error("boost::math::owens_t", "selection routine in Owen's T function failed with h = %1%", h, pol); } return val; } @@ -1047,11 +1045,6 @@ namespace boost { typedef typename tools::promote_args::type result_type; typedef typename policies::evaluation::type value_type; - typedef typename policies::precision::type precision_type; - typedef std::integral_constant tag_type; return policies::checked_narrowing_cast(detail::owens_t(static_cast(h), static_cast(a), pol), "boost::math::owens_t<%1%>(%1%,%1%)"); } diff --git a/include/boost/math/special_functions/prime.hpp b/include/boost/math/special_functions/prime.hpp index 5bfe6f749e..35d9c1a470 100644 --- a/include/boost/math/special_functions/prime.hpp +++ b/include/boost/math/special_functions/prime.hpp @@ -2416,8 +2416,7 @@ constexpr std::array prime_data_imp::a3; return prime_data::a2[n - prime_data::b1 - 1]; if(n >= prime_data::b3) { - return boost::math::policies::raise_domain_error( - "boost::math::prime<%1%>", "Argument n out of range: got %1%", n, pol); + return boost::math::policies::raise_domain_error("boost::math::prime<%1%>", "Argument n out of range: got %1%", n, pol); } return static_cast(prime_data::a3[n - prime_data::b2 - 1]) + 0xFFFFu; } diff --git a/include/boost/math/special_functions/trigamma.hpp b/include/boost/math/special_functions/trigamma.hpp index 87b17fb7d8..7ac99466cb 100644 --- a/include/boost/math/special_functions/trigamma.hpp +++ b/include/boost/math/special_functions/trigamma.hpp @@ -392,11 +392,7 @@ BOOST_MATH_GPU_ENABLED T trigamma_dispatch(T x, const Policy& pol, const Tag& ta // Reflect: T z = 1 - x; - if(z < 1) - { - result = 1 / (z * z); - z += 1; - } + BOOST_MATH_ASSERT(z >= 1); // Argument reduction for tan: if(floor(x) == x) diff --git a/include/boost/math/special_functions/ulp.hpp b/include/boost/math/special_functions/ulp.hpp index 5d1617aced..5805c171a3 100644 --- a/include/boost/math/special_functions/ulp.hpp +++ b/include/boost/math/special_functions/ulp.hpp @@ -29,9 +29,7 @@ T ulp_imp(const T& val, const std::true_type&, const Policy& pol) if(fpclass == FP_NAN) { - return policies::raise_domain_error( - function, - "Argument must be finite, but got %1%", val, pol); + return policies::raise_domain_error(function, "Argument must be finite, but got %1%", val, pol); } else if((fpclass == (int)FP_INFINITE) || (fabs(val) >= tools::max_value())) { @@ -63,9 +61,7 @@ T ulp_imp(const T& val, const std::false_type&, const Policy& pol) if(fpclass == FP_NAN) { - return policies::raise_domain_error( - function, - "Argument must be finite, but got %1%", val, pol); + return policies::raise_domain_error(function,"Argument must be finite, but got %1%", val, pol); } else if((fpclass == FP_INFINITE) || (fabs(val) >= tools::max_value())) { @@ -81,7 +77,7 @@ T ulp_imp(const T& val, const std::false_type&, const Policy& pol) T diff = scalbn(T(1), expon - std::numeric_limits::digits); if(diff == 0) diff = detail::get_smallest_value(); - return diff; + return diff; // LCOV_EXCL_LINE previous lines are covered so this one must be too. } } diff --git a/include/boost/math/special_functions/zeta.hpp b/include/boost/math/special_functions/zeta.hpp index c53611b914..4a374cdd5f 100644 --- a/include/boost/math/special_functions/zeta.hpp +++ b/include/boost/math/special_functions/zeta.hpp @@ -152,27 +152,29 @@ T zeta_polynomial_series(T s, T sc, Policy const &) // BOOST_MATH_STD_USING int n = itrunc(T(log(boost::math::tools::epsilon()) / -2)); - T sum = 0; + T sum = 0; // LCOV_EXCL_LINE spurious miss as surrounding lines hit. T two_n = ldexp(T(1), n); - int ej_sign = 1; + int ej_sign = 1; // LCOV_EXCL_LINE spurious miss as surrounding lines hit. for(int j = 0; j < n; ++j) { sum += ej_sign * -two_n / pow(T(j + 1), s); ej_sign = -ej_sign; } - T ej_sum = 1; - T ej_term = 1; + T ej_sum = 1; // LCOV_EXCL_LINE spurious miss as surrounding lines hit. + T ej_term = 1; // LCOV_EXCL_LINE spurious miss as surrounding lines hit. for(int j = n; j <= 2 * n - 1; ++j) { sum += ej_sign * (ej_sum - two_n) / pow(T(j + 1), s); ej_sign = -ej_sign; ej_term *= 2 * n - j; ej_term /= j - n + 1; - ej_sum += ej_term; + ej_sum += ej_term; // LCOV_EXCL_LINE spurious miss as surrounding lines hit. } return -sum / (two_n * (-powm1(T(2), sc))); } - +// +// MP only, verified as covered by the full tests: +// LCOV_EXCL_START template T zeta_imp_prec(T s, T sc, const Policy& pol, const std::integral_constant&) { @@ -197,6 +199,7 @@ T zeta_imp_prec(T s, T sc, const Policy& pol, const std::integral_constant inline T zeta_imp_prec(T s, T sc, const Policy&, const std::integral_constant&) @@ -372,13 +375,9 @@ inline T zeta_imp_prec(T s, T sc, const Policy&, const std::integral_constant& result = tools::evaluate_polynomial(P, T(s - 15)) / tools::evaluate_polynomial(Q, T(s - 15)); result = 1 + exp(result); } - else if(s < 63) - { - result = 1 + pow(T(2), -s); - } else { - result = 1; + result = 1 + pow(T(2), -s); } return result; } @@ -897,13 +892,9 @@ T zeta_imp_prec(T s, T sc, const Policy&, const std::integral_constant result = tools::evaluate_polynomial(P, T(s - 30)) / tools::evaluate_polynomial(Q, T(s - 30)); result = 1 + exp(result); } - else if(s < 117) - { - result = 1 + pow(T(2), -s); - } else { - result = 1; + result = 1 + pow(T(2), -s); } return result; } @@ -930,11 +921,11 @@ T zeta_imp_odd_integer(int s, const T& sc, const Policy& pol, const std::false_t static BOOST_MATH_THREAD_LOCAL T results[50] = {}; static BOOST_MATH_THREAD_LOCAL int digits = tools::digits(); // LCOV_EXCL_STOP - int current_digits = tools::digits(); + int current_digits = tools::digits(); // LCOV_EXCL_LINE spurious miss as surrounding lines hit. if(digits != current_digits) { // Oh my precision has changed... - is_init = false; + is_init = false; // LCOV_EXCL_LINE variable precision MP case only, not included in coverage tests. } if(!is_init) { @@ -943,7 +934,7 @@ T zeta_imp_odd_integer(int s, const T& sc, const Policy& pol, const std::false_t for(unsigned k = 0; k < sizeof(results) / sizeof(results[0]); ++k) { T arg = k * 2 + 3; - T c_arg = 1 - arg; + T c_arg = 1 - arg; // LCOV_EXCL_LINE spurious miss as surrounding lines hit. results[k] = zeta_polynomial_series(arg, c_arg, pol); } } @@ -957,11 +948,8 @@ T zeta_imp(T s, T sc, const Policy& pol, const Tag& tag) BOOST_MATH_STD_USING static const char* function = "boost::math::zeta<%1%>"; if(sc == 0) - return policies::raise_pole_error( - function, - "Evaluation of zeta function at pole %1%", - s, pol); - T result; + return policies::raise_pole_error(function, "Evaluation of zeta function at pole %1%", s, pol); + T result; // LCOV_EXCL_LINE // // Trivial case: // @@ -1003,7 +991,7 @@ T zeta_imp(T s, T sc, const Policy& pol, const Tag& tag) #ifndef BOOST_MATH_NO_EXCEPTIONS } catch(const boost::math::rounding_error&){} // Just fall through, s is too large to round - catch(const std::overflow_error&){} + catch(const std::overflow_error&){} // LCOV_EXCL_LINE We can only get here for "strange" MP types with small exponents and very large digit counts. #endif } @@ -1026,8 +1014,13 @@ T zeta_imp(T s, T sc, const Policy& pol, const Tag& tag) if(result > tools::log_max_value()) return sign(mult) * policies::raise_overflow_error(function, nullptr, pol); result = exp(result); + // + // Whether this if branch can be triggered is very type dependent, we need + // result to be just on the verge of overflow when /s/ is very close to a + // half integer. + // if(tools::max_value() / fabs(mult) < result) - return boost::math::sign(mult) * policies::raise_overflow_error(function, nullptr, pol); + return boost::math::sign(mult) * policies::raise_overflow_error(function, nullptr, pol); // LCOV_EXCL_LINE result *= mult; } else diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d94d40c5c6..fe3f9c9a94 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -101,19 +101,23 @@ local float128_type_intel_quad = local float128_type_gcc = [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : gcc:quadmath gcc:BOOST_MATH_TEST_FLOAT128 ] ; -local float128_type_floatmax = +local float128_type_floatmax = $(float128_type_gcc) $(float128_type_intel_quad) [ check-target-builds ../config//has_128bit_floatmax_t "128-bit floatmax_t" : : no ] ; +# +# DO NOT include $(float128_type_floatmax) in this macro, otherwise the whole test +# gets disabled when std::float128_t is not available (which is most of the time!!) +# local float128_type = - $(float128_type_intel_quad) $(float128_type_gcc) $(float128_type_floatmax) ; + $(float128_type_intel_quad) $(float128_type_gcc) ; test-suite special_fun : [ run test_1F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=1 : test_1F0_1 ] # hypergeometric_pFq_checked_series.hpp uses auto, the rest are from quadrature tests. [ run test_1F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=2 : test_1F0_2 ] # hypergeometric_pFq_checked_series.hpp uses auto, the rest are from quadrature tests. [ run test_1F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=3 : test_1F0_3 ] # hypergeometric_pFq_checked_series.hpp uses auto, the rest are from quadrature tests. - [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] $(float128_type) TEST=1 : test_2F0_1 ] - [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] $(float128_type) TEST=2 : test_2F0_2 ] - [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] $(float128_type) TEST=3 : test_2F0_3 ] - [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] $(float128_type) TEST=4 : test_2F0_4 ] + [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=1 : test_2F0_1 ] + [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=2 : test_2F0_2 ] + [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] $(float128_type_gcc) TEST=3 : test_2F0_3 ] + [ run test_2F0.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=4 : test_2F0_4 ] [ run test_0F1.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=1 : test_0F1_1 ] [ run test_0F1.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_smart_ptr ] TEST=2 : test_0F1_2 ] @@ -180,6 +184,7 @@ test-suite special_fun : [ run log1p_expm1_test.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] [ run log1p_expm1_extra_test.cpp pch_light /boost/test//boost_unit_test_framework : : : [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : -lquadmath ] ] [ run log1p_expm1_stdfloat_test.cpp pch_light /boost/test//boost_unit_test_framework ] + [ run test_log1p_simple.cpp ] [ run powm1_sqrtp1m1_test.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] [ run git_issue_705.cpp /boost/test//boost_unit_test_framework ] [ run git_issue_810.cpp /boost/test//boost_unit_test_framework ] @@ -246,6 +251,7 @@ test-suite special_fun : [ run erf_limits_test.cpp ] [ run test_expint.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] [ run test_factorials.cpp pch /boost/test//boost_unit_test_framework ] + [ run test_lanczos.cpp /boost/test//boost_unit_test_framework : : : $(float128_type) ] [ run test_gamma.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] [ run test_gamma_edge.cpp ] [ run test_gamma_mp.cpp /boost/test//boost_unit_test_framework : : : release TEST=1 [ check-target-builds ../config//is_ci_sanitizer_run "Sanitizer CI run" : no ] : test_gamma_mp_1 ] @@ -546,7 +552,7 @@ test-suite special_fun : [ run test_lambert_w_integrals_long_double.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_smart_ptr cxx11_unified_initialization_syntax sfinae_expr ] ] [ run test_lambert_w_integrals_double.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_smart_ptr cxx11_unified_initialization_syntax sfinae_expr ] ] [ run test_lambert_w_integrals_float.cpp /boost/test//boost_unit_test_framework : : : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_smart_ptr cxx11_unified_initialization_syntax sfinae_expr ] ] - [ run test_lambert_w_derivative.cpp /boost/test//boost_unit_test_framework : : : BOOST_MATH_TEST_MULTIPRECISION $(float128_type) ] + [ run test_lambert_w_derivative.cpp /boost/test//boost_unit_test_framework : : : BOOST_MATH_TEST_MULTIPRECISION $(float128_type_gcc) ] [ run test_legendre.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework : : : $(float128_type) ] [ run chebyshev_test.cpp : : : [ requires cxx11_inline_namespaces cxx11_unified_initialization_syntax cxx11_hdr_tuple cxx11_smart_ptr cxx11_defaulted_functions cxx11_auto_declarations cxx11_range_based_for cxx11_constexpr ] $(float128_type) ] @@ -563,7 +569,7 @@ test-suite special_fun : [ run test_ldouble_simple.cpp /boost/test//boost_unit_test_framework ] # Needs to run in release mode, as it's rather slow: - [ run test_next.cpp pch /boost/test//boost_unit_test_framework : : : release ] + [ run test_next.cpp pch /boost/test//boost_unit_test_framework ] [ run test_next_decimal.cpp pch /boost/test//boost_unit_test_framework : : : release ] [ run test_owens_t.cpp /boost/test//boost_unit_test_framework ] [ run test_polygamma.cpp test_instances//test_instances pch_light /boost/test//boost_unit_test_framework ] @@ -580,6 +586,7 @@ test-suite special_fun : [ run test_zeta.cpp /boost/test//boost_unit_test_framework test_instances//test_instances pch_light ] [ run test_sinc.cpp /boost/test//boost_unit_test_framework pch_light ] [ run test_fibonacci.cpp /boost/test//boost_unit_test_framework ] + [ run test_prime.cpp /boost/test//boost_unit_test_framework ] ; test-suite distribution_tests : @@ -889,6 +896,7 @@ test-suite distribution_tests : [ run test_legacy_nonfinite.cpp /boost/test//boost_unit_test_framework ] [ run test_basic_nonfinite.cpp /boost/test//boost_unit_test_framework ] + [ run test_nonfinite_io.cpp /boost/test//boost_unit_test_framework ] [ run test_lexical_cast.cpp /boost/test//boost_unit_test_framework ] [ run test_nonfinite_trap.cpp /boost/test//boost_unit_test_framework : : : off:no ] [ run test_signed_zero.cpp /boost/test//boost_unit_test_framework ] @@ -1061,6 +1069,7 @@ test-suite misc : quaternion_mi1.cpp quaternion_mi2.cpp /boost/test//boost_unit_test_framework ] + [ run test_ulp.cpp /boost/test//boost_unit_test_framework ] # [ run __temporary_test.cpp test_instances//test_instances : : : always_show_run_output off ] ; @@ -1380,7 +1389,7 @@ rule get_float128_tests : # command line : # input files : # requirements - $(float128_type) + $(float128_type_floatmax) BOOST_ALL_NO_LIB : $(source:B)_floatmax_t ] ; } diff --git a/test/compile_test/instantiate.hpp b/test/compile_test/instantiate.hpp index 85c85f785d..410d50d890 100644 --- a/test/compile_test/instantiate.hpp +++ b/test/compile_test/instantiate.hpp @@ -1749,11 +1749,6 @@ void instantiate_mixed(RealType) boost::math::owens_t(fr, dr, pol); boost::math::owens_t(i, s, pol); boost::math::lambert_w0(i, pol); - { - int i_zero { 0 }; - - boost::math::lambert_wm1(i_zero, pol); - } boost::math::lambert_w0_prime(i, pol); #endif #ifdef TEST_GROUP_11 @@ -1950,11 +1945,6 @@ void instantiate_mixed(RealType) test::owens_t(fr, dr); test::owens_t(i, s); boost::math::lambert_w0(i); - { - int i_zero { 0 }; - - boost::math::lambert_wm1(i_zero); - } boost::math::lambert_w0_prime(i); #endif #endif diff --git a/test/legendre_stieltjes_test.cpp b/test/legendre_stieltjes_test.cpp index c504456194..6fda15099e 100644 --- a/test/legendre_stieltjes_test.cpp +++ b/test/legendre_stieltjes_test.cpp @@ -129,6 +129,10 @@ void test_legendre_stieltjes() BOOST_CHECK_SMALL(En(zero), 50*tol); } } + +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(legendre_stieltjes(0), std::domain_error); +#endif } diff --git a/test/log1p_expm1_test.hpp b/test/log1p_expm1_test.hpp index 886e26d254..3637f992f5 100644 --- a/test/log1p_expm1_test.hpp +++ b/test/log1p_expm1_test.hpp @@ -79,12 +79,13 @@ void test(T, const char* type_name) BOOST_CHECK_EQUAL(boost::math::expm1(T(-std::numeric_limits::infinity())), m_one); BOOST_CHECK_EQUAL(boost::math::expm1(std::numeric_limits::infinity()), std::numeric_limits::infinity()); #ifndef BOOST_BORLANDC -#ifndef BOOST_NO_EXCEPTIONS +#ifndef BOOST_MATH_NO_EXCEPTIONS // When building with Borland's compiler, simply the *presence* // of these tests cause other unrelated tests to fail!!! :-( using namespace boost::math::policies; typedef policy > pol; BOOST_MATH_CHECK_THROW(boost::math::log1p(m_one, pol()), std::overflow_error); + BOOST_MATH_CHECK_THROW(boost::math::log1p(static_cast(-2), pol()), std::domain_error); BOOST_MATH_CHECK_THROW(boost::math::expm1(std::numeric_limits::infinity(), pol()), std::overflow_error); #endif #endif diff --git a/test/logaddexp_test.cpp b/test/logaddexp_test.cpp index d0793f27ad..ed538025c4 100644 --- a/test/logaddexp_test.cpp +++ b/test/logaddexp_test.cpp @@ -41,8 +41,10 @@ void test() Real spot1 = static_cast(exp(x1)); Real spot2 = static_cast(exp(x2)); Real spot12 = logaddexp(x1, x2); + Real spot21 = logaddexp(x2, x1); CHECK_ULP_CLOSE(log(spot1 + spot2), spot12, 1); + CHECK_ULP_CLOSE(log(spot1 + spot2), spot21, 1); } int main (void) diff --git a/test/powm1_sqrtp1m1_test.hpp b/test/powm1_sqrtp1m1_test.hpp index 12871bbd7e..86f4e4a7ef 100644 --- a/test/powm1_sqrtp1m1_test.hpp +++ b/test/powm1_sqrtp1m1_test.hpp @@ -1606,5 +1606,20 @@ void test_powm1_sqrtp1m1(T, const char* type_name) extract_result(2)); handle_test_result(result, powm1_big_data[result.worst()], result.worst(), type_name, "boost::math::powm1", "powm1"); + // + // Special cases and code coverage: + // + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_quiet_NaN) + { + BOOST_MATH_CHECK_THROW(boost::math::powm1(std::numeric_limits::quiet_NaN(), static_cast(2.0)), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::powm1(static_cast(3.5), std::numeric_limits::quiet_NaN()), std::domain_error); + } + + BOOST_CHECK_EQUAL(boost::math::powm1(static_cast(-2.0), static_cast(4)), static_cast(15)); + BOOST_CHECK_EQUAL(boost::math::powm1(static_cast(-3.0), static_cast(4)), static_cast(80)); + BOOST_CHECK_EQUAL(boost::math::powm1(static_cast(-3.0), static_cast(3)), static_cast(-28)); + BOOST_CHECK_EQUAL(boost::math::powm1(-static_cast(0.0), static_cast(3)), static_cast(-1)); + BOOST_MATH_CHECK_THROW(boost::math::powm1(static_cast(-3.5), static_cast(2.25)), std::domain_error); + } diff --git a/test/sinc_test.hpp b/test/sinc_test.hpp index 4d1caa0c8c..67fb142a78 100644 --- a/test/sinc_test.hpp +++ b/test/sinc_test.hpp @@ -13,9 +13,11 @@ #include +#include #define BOOST_TEST_MAIN #include +#include BOOST_TEST_CASE_TEMPLATE_FUNCTION(sinc_pi_test, T) @@ -53,6 +55,27 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(sinc_pi_complex_test, T) (abs(sinc_pi(::std::complex(0, 1))- ::std::complex(sinh(static_cast(1))))) (numeric_limits::epsilon())); + + // + // A very poor test with rather large tolerance for failure. + // But it does get out coverage up! + // + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::is_specialized && std::numeric_limits::digits < 60) + { + T tolerance = std::numeric_limits::epsilon() * 20000; + + std::complex val(1, 2); + for (unsigned i = 0; i < 5; ++i) + { + using mp_t = boost::multiprecision::cpp_complex_100; + val /= 3; + std::complex r1, r2; + r1 = sinc_pi(val); + r2 = static_cast>(sin(mp_t(val)) / mp_t(val)); + BOOST_CHECK_CLOSE_FRACTION(arg(r1), arg(r2), tolerance); + BOOST_CHECK_CLOSE_FRACTION(abs(r1), abs(r2), tolerance); + } + } } diff --git a/test/sinhc_test.hpp b/test/sinhc_test.hpp index b50bd2e67d..912e8b5488 100644 --- a/test/sinhc_test.hpp +++ b/test/sinhc_test.hpp @@ -13,9 +13,11 @@ #include +#include #define BOOST_TEST_MAIN #include +#include BOOST_TEST_CASE_TEMPLATE_FUNCTION(sinhc_pi_test, T) @@ -33,6 +35,19 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(sinhc_pi_test, T) BOOST_CHECK_PREDICATE(::std::less_equal(), (abs(sinhc_pi(static_cast(0))-static_cast(1))) (numeric_limits::epsilon())); + + using mp_t = boost::multiprecision::cpp_bin_float_50; + T val = 2; + T tolerance = boost::math::tools::epsilon() * 100; + for (unsigned i = 0; i < 1000; ++i) + { + val /= 3; + if (val < boost::math::tools::min_value()) + break; + T r1 = sinhc_pi(val); + T r2 = static_cast(sinh(mp_t(val)) / mp_t(val)); + BOOST_CHECK_CLOSE_FRACTION(r1, r2, tolerance); + } } @@ -53,6 +68,19 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(sinhc_pi_complex_test, T) (abs(sinhc_pi(::std::complex(0, 1))- ::std::complex(sin(static_cast(1))))) (numeric_limits::epsilon())); + + using mp_t = boost::multiprecision::cpp_complex_50; + std::complex val(2, 2.5); + for (unsigned i = 0; i < 50; ++i) + { + val /= 3; + if (val.real() < boost::math::tools::min_value()) + break; + std::complex r1 = sinhc_pi(val); + std::complex r2 = static_cast>(sinh(mp_t(val)) / mp_t(val)); + BOOST_CHECK_LE(std::abs(r1.real() - r2.real()), boost::math::tools::epsilon()); + BOOST_CHECK_LE(std::abs(r1.imag() - r2.imag()), boost::math::tools::epsilon()); + } } diff --git a/test/test_basic_nonfinite.cpp b/test/test_basic_nonfinite.cpp index 20f0e222c9..c279be9ae6 100644 --- a/test/test_basic_nonfinite.cpp +++ b/test/test_basic_nonfinite.cpp @@ -163,6 +163,19 @@ template void basic_test_inf_impl() BOOST_CHECK(b2 == a2); BOOST_CHECK(b3 == std::numeric_limits::infinity()); BOOST_CHECK(ss.rdstate() == std::ios_base::eofbit); + + ss.clear(); + ss.str(S_("")); + ss << "ind"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit); + + ss.clear(); + ss.str(S_("")); + ss << "infinidy"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit); + } //------------------------------------------------------------------------------ @@ -221,6 +234,56 @@ template void basic_test_nan_impl() BOOST_CHECK(!(signbit)(b5)); BOOST_CHECK(ss.rdstate() == std::ios_base::eofbit); + + ss.clear(); + ss.str(S_("")); + ss << "nad"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit); + + ss.clear(); + ss.str(S_("")); + ss << "nan(123"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit | std::ios_base::eofbit); + + ss.clear(); + ss.str(S_("")); + ss << "qnad"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit | std::ios_base::eofbit); + + std::locale new_locale_2(tmp_locale, new nonfinite_num_get(legacy)); + ss.imbue(new_locale_2); + ss.clear(); + ss.str(S_("")); + ss << "qnan"; + ss >> b1; + BOOST_CHECK((boost::math::isnan)(b1)); + + ss.clear(); + ss.str(S_("")); + ss << "qnad"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit | std::ios_base::eofbit); + + ss.clear(); + ss.str(S_("")); + ss << "1.#SNAD"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit | std::ios_base::eofbit); + + ss.clear(); + ss.str(S_("")); + ss << "1.#POP"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit | std::ios_base::eofbit); + + ss.clear(); + ss.str(S_("")); + ss << "1.#IMP"; + ss >> b1; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit | std::ios_base::eofbit); } //------------------------------------------------------------------------------ diff --git a/test/test_jacobi.hpp b/test/test_jacobi.hpp index 186def46b6..ce2ec9c4e8 100644 --- a/test/test_jacobi.hpp +++ b/test/test_jacobi.hpp @@ -186,5 +186,33 @@ void test_spots(T, const char* type_name) BOOST_CHECK_CLOSE_FRACTION(boost::math::jacobi_sn(T(0.5), T(0.5)), static_cast(0.475082936028536510082218324703870258745078171807428948028252L), tol); BOOST_CHECK_CLOSE_FRACTION(boost::math::jacobi_sn(T(0.5), T(0.5), pol), static_cast(0.475082936028536510082218324703870258745078171807428948028252L), tol); + // + // Bug cases and coverage: + // +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(boost::math::jacobi_cd(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_cn(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_cs(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_dn(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_ds(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_nc(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_nd(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_ns(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_sc(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_sd(T(-0.5), T(0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_sn(T(-0.5), T(0.5)), std::domain_error); +#else + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_cd(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_cn(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_cs(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_dn(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_ds(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_nc(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_nd(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_ns(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_sc(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_sd(T(-0.5), T(0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_sn(T(-0.5), T(0.5)))); +#endif } diff --git a/test/test_jacobi_theta.hpp b/test/test_jacobi_theta.hpp index 259e41027e..472f37350c 100644 --- a/test/test_jacobi_theta.hpp +++ b/test/test_jacobi_theta.hpp @@ -298,6 +298,37 @@ void test_spots(T, const char* type_name) #include "jacobi_theta_small_tau.ipp" do_test_jacobi_theta_tau(jacobi_theta_small_tau_data, type_name, "Jacobi Theta: Random Data (Small Tau)"); + + // + // coverage and bugs: + // +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(boost::math::jacobi_theta4(T(0.5), T(0)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4(T(0.5), T(-0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4(T(0.5), T(1)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4(T(0.5), T(1.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4m1(T(0.5), T(0)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4m1(T(0.5), T(-0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4m1(T(0.5), T(1)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta4m1(T(0.5), T(1.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta3m1(T(0.5), T(0)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta3m1(T(0.5), T(-0.5)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta3m1(T(0.5), T(1)), std::domain_error); + BOOST_CHECK_THROW(boost::math::jacobi_theta3m1(T(0.5), T(1.5)), std::domain_error); +#else + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4(T(0.5), T(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4(T(0.5), T(-0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4(T(0.5), T(1)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4(T(0.5), T(1.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4m1(T(0.5), T(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4m1(T(0.5), T(-0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4m1(T(0.5), T(1)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta4m1(T(0.5), T(1.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta3m1(T(0.5), T(0)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta3m1(T(0.5), T(-0.5)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta3m1(T(0.5), T(1)))); + BOOST_CHECK((boost::math::isnan)(boost::math::jacobi_theta3m1(T(0.5), T(1.5)))); +#endif } #define _check_close(a, b, eps) \ diff --git a/test/test_laguerre.hpp b/test/test_laguerre.hpp index a0542d1214..8f49b681c4 100644 --- a/test/test_laguerre.hpp +++ b/test/test_laguerre.hpp @@ -135,5 +135,8 @@ void test_spots(T, const char* t) BOOST_CHECK_CLOSE_FRACTION(::boost::math::laguerre(10, 6, static_cast(8.5L)), static_cast(20.51596541066649098875661375661375661376L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::laguerre(10, 12, static_cast(12.5L)), static_cast(-199.5560968456234671241181657848324514991L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::laguerre(50, 40, static_cast(12.5L)), static_cast(-4.996769495006119488583146995907246595400e16L), tolerance); + + BOOST_CHECK_EQUAL(::boost::math::laguerre(0, T(40)), T(1)); + BOOST_CHECK_EQUAL(::boost::math::laguerre(0, T(400)), T(1)); } diff --git a/test/test_lambert_w.cpp b/test/test_lambert_w.cpp index 33269e68dd..e0cbd24f66 100644 --- a/test/test_lambert_w.cpp +++ b/test/test_lambert_w.cpp @@ -352,6 +352,11 @@ void test_spots(RealType) #ifndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(lambert_w0(-1.), std::domain_error); BOOST_CHECK_THROW(lambert_wm1(-1.), std::domain_error); + BOOST_CHECK_THROW(lambert_wm1(1.), std::domain_error); + if (std::numeric_limits::has_denorm) + { + BOOST_CHECK_THROW(lambert_wm1(-std::numeric_limits::denorm_min()), std::overflow_error); + } if (std::numeric_limits::has_quiet_NaN) { BOOST_CHECK_THROW(lambert_w0(std::numeric_limits::quiet_NaN()), std::domain_error); // Would be NaN. @@ -592,10 +597,11 @@ void test_spots(RealType) BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868), tolerance); // -64.0265121 - if (std::numeric_limits::has_infinity) - { - BOOST_CHECK_EQUAL(lambert_wm1(0), -std::numeric_limits::infinity()); - } +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(lambert_wm1(0), std::overflow_error); +#else + BOOST_CHECK_EQUAL(lambert_wm1(0), -std::numeric_limits::infinity()); +#endif if (std::numeric_limits::has_quiet_NaN) { // BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits::quiet_NaN()), +std::numeric_limits::infinity()); // message is: @@ -803,6 +809,17 @@ void test_spots(RealType) BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.0)), BOOST_MATH_TEST_VALUE(RealType, 0.0), tolerance); + + // + // Extra coverage: + // + BOOST_CHECK_EQUAL(boost::math::lambert_w0_prime(BOOST_MATH_TEST_VALUE(RealType, 0.0)), BOOST_MATH_TEST_VALUE(RealType, 1.0)); +#ifndef BOOST_MATH_NO_EXEPTIONS + BOOST_CHECK_THROW(boost::math::lambert_w0_prime(-boost::math::constants::exp_minus_one()), std::overflow_error); + BOOST_CHECK_THROW(boost::math::lambert_wm1_prime(-boost::math::constants::exp_minus_one()), std::overflow_error); + BOOST_CHECK_THROW(boost::math::lambert_wm1_prime(BOOST_MATH_TEST_VALUE(RealType, 0.0)), std::overflow_error); +#endif + // these fail for cpp_dec_float_50 // 'boost::multiprecision::detail::expression,boost::multiprecision::et_on>,void,void,void>' // : no appropriate default constructor available @@ -1149,8 +1166,11 @@ BOOST_AUTO_TEST_CASE( test_range_of_double_values ) // For z = 0, W = -infinity if (std::numeric_limits::has_infinity) { - BOOST_CHECK_EQUAL(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, 0.)), - -std::numeric_limits::infinity()); +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, 0.)), std::overflow_error); +#else + BOOST_CHECK_EQUAL(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, 0.)), -std::numeric_limits::infinity()); +#endif } #elif BOOST_MATH_TEST_MULTIPRECISION == 2 diff --git a/test/test_lanczos.cpp b/test/test_lanczos.cpp new file mode 100644 index 0000000000..afdcd4372d --- /dev/null +++ b/test/test_lanczos.cpp @@ -0,0 +1,79 @@ +// Copyright John Maddock 2025. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#define BOOST_TEST_MAIN +#include +#include + +#include +#include + +#include + + +template +T fake_lgamma(T x, const Policy& pol) +{ + typedef typename boost::math::lanczos::lanczos::type lanczos_type; + T xm1 = static_cast(x - 1); + T xm2 = static_cast(x - 2); + return boost::math::detail::lgamma_small_imp(x, xm1, xm2, boost::math::integral_constant(), pol, lanczos_type()); +} + +template +T fake_beta(T x, T y, const Policy& pol) +{ + typedef typename boost::math::lanczos::lanczos::type lanczos_type; + return boost::math::detail::beta_imp(x, y, lanczos_type(), pol); +} + +template +void test_lanczos() +{ + static const T gamma_values[5][2] = { + { static_cast(0.9990234375), BOOST_MATH_BIG_CONSTANT(T, 1000, 0.0005644719118551233842574575277837954032273381467111560151573964333623759876693326772975355235763579669851459698347791150664129556238023435782509) }, + { static_cast(1.0009765625), BOOST_MATH_BIG_CONSTANT(T, 1000, -0.00056290317999120463170214992168514502772879541390257627479851327242521375496316078955498047974490391404458478547041900753228681266105375203395) }, + { static_cast(1.9990234375), BOOST_MATH_BIG_CONSTANT(T, 1000, -0.00041256773597148940171061762396967043263766321508278648166258325752450997988091121880044028815700667736697239273636914229467280307848301056348) }, + { static_cast(2.0009765625), BOOST_MATH_BIG_CONSTANT(T, 1000, 0.0004131827930642542642586749863320416448830389198819599629600850019751583690627183743966471144142533038637004476283413018111524526428991161605850) }, + { static_cast(15.5), BOOST_MATH_BIG_CONSTANT(T, 1000, 26.536914491115613623952954502438732190637095031219293570786654851418392173706059728481291108517001108710291135377351053352153160697114162788268) }, + }; + + + T tolerance = boost::math::tools::epsilon() * 10000; // tolerance as a PERSENTAGE + + for (unsigned i = 0; i < 5; ++i) + { + BOOST_CHECK_CLOSE(fake_lgamma(gamma_values[i][0], Policy()), gamma_values[i][1], tolerance); + } + + static const T beta_values[3][3] = { + { static_cast(3.5), static_cast(5.5), BOOST_MATH_BIG_CONSTANT(T, 1000, 0.0043143209659283659585821213454460946590842475272180103132285310868485027552148255901569081768919454363768513150969758239477301943185356506478162) }, + { static_cast(3.5), static_cast(7.5), BOOST_MATH_BIG_CONSTANT(T, 1000, 0.0017137441614659898113256759788855320451362427677560429855324442928314885944325557205345496369320783261163603834968542856236817160765294390073270) }, + { static_cast(3.5), static_cast(9.5), BOOST_MATH_BIG_CONSTANT(T, 1000, 0.0008276605325261882611516048761663080899805717912458162146037373005152075598111774786672540860183332824993785943024580356705281015142329677024022) }, + }; + + for (unsigned i = 0; i < 3; ++i) + { + BOOST_CHECK_CLOSE(fake_beta(beta_values[i][0], beta_values[i][1], Policy()), beta_values[i][2], tolerance); + } +} + + +int main() +{ + test_lanczos>>(); + test_lanczos>>(); + test_lanczos>(); + + test_lanczos>(); + test_lanczos>(); + test_lanczos>(); + test_lanczos>, boost::math::policies::policy<>>(); + test_lanczos>, boost::math::policies::policy<>>(); + test_lanczos>, boost::math::policies::policy<>>(); + test_lanczos>, boost::math::policies::policy<>>(); + test_lanczos>, boost::math::policies::policy<>>(); +} diff --git a/test/test_legendre.cpp b/test/test_legendre.cpp index 7551fdd605..bc32892577 100644 --- a/test/test_legendre.cpp +++ b/test/test_legendre.cpp @@ -52,7 +52,7 @@ void expected_results() // // Linux: // - if((std::numeric_limits::digits <= 64) + BOOST_MATH_IF_CONSTEXPR((std::numeric_limits::digits <= 64) && (std::numeric_limits::digits != std::numeric_limits::digits)) { #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS @@ -65,7 +65,7 @@ void expected_results() ".*", 10, 5); // test function #endif } - if(std::numeric_limits::digits == 64) + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::digits == 64) { add_expected_result( ".*", // compiler diff --git a/test/test_legendre.hpp b/test/test_legendre.hpp index 1a85050f87..885dae91e8 100644 --- a/test/test_legendre.hpp +++ b/test/test_legendre.hpp @@ -158,7 +158,7 @@ void test_spots(T, const char* t) BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(-4, 2, static_cast(0.5L)), static_cast(5.625000000000000000000000000000000000000L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(7, 5, static_cast(0.5L)), static_cast(-5696.789530152175143607977274672800795328L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(-7, 4, static_cast(0.5L)), static_cast(465.1171875000000000000000000000000000000L), tolerance); - if(std::numeric_limits::max_exponent > std::numeric_limits::max_exponent) + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::max_exponent > std::numeric_limits::max_exponent) { BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(40, 30, static_cast(0.5L)), static_cast(-7.855722083232252643913331343916012143461e45L), tolerance); } @@ -167,7 +167,7 @@ void test_spots(T, const char* t) BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(-4, 2, static_cast(-0.5L)), static_cast(-5.625000000000000000000000000000000000000L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(7, 5, static_cast(-0.5L)), static_cast(-5696.789530152175143607977274672800795328L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(-7, 4, static_cast(-0.5L)), static_cast(465.1171875000000000000000000000000000000L), tolerance); - if(std::numeric_limits::max_exponent > std::numeric_limits::max_exponent) + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::max_exponent > std::numeric_limits::max_exponent) { BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(40, 30, static_cast(-0.5L)), static_cast(-7.855722083232252643913331343916012143461e45L), tolerance); } @@ -199,6 +199,17 @@ void test_spots(T, const char* t) BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(2, -2, static_cast(0.5)), static_cast(0.09375L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(2, -2, static_cast(1)), static_cast(0), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::legendre_p(2, -2, static_cast(0)), static_cast(0.125), tolerance); + // + // Coverage: + // +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(boost::math::legendre_p(2, -1.1), std::domain_error); + BOOST_CHECK_THROW(boost::math::legendre_p(2, 1.1), std::domain_error); + BOOST_CHECK_THROW(boost::math::legendre_p(2, 3, -1.1), std::domain_error); + BOOST_CHECK_THROW(boost::math::legendre_p(2, 3, 1.1), std::domain_error); +#endif + BOOST_CHECK_EQUAL(boost::math::legendre_p(2, 3, 0.5), T(0)); + BOOST_CHECK_EQUAL(boost::math::legendre_p(2, 6, 0.5), T(0)); } template @@ -275,6 +286,23 @@ void test_legendre_p_prime() } ++n; } + // + // Coverage: + // +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_CHECK_THROW(boost::math::legendre_p_prime(2, -1.1), std::domain_error); + BOOST_CHECK_THROW(boost::math::legendre_p_prime(2, 1.1), std::domain_error); +#endif + std::vector a, b; + a = boost::math::legendre_p_zeros(0); + b = boost::math::legendre_p_zeros(-1); + BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end()); + a = boost::math::legendre_p_zeros(1); + b = boost::math::legendre_p_zeros(-2); + BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end()); + a = boost::math::legendre_p_zeros(5); + b = boost::math::legendre_p_zeros(-6); + BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end()); } template diff --git a/test/test_log1p_simple.cpp b/test/test_log1p_simple.cpp index ef6c204d4c..816f3f8fe1 100644 --- a/test/test_log1p_simple.cpp +++ b/test/test_log1p_simple.cpp @@ -34,6 +34,18 @@ void test_log1pmx() const T value (dist(rng)); CHECK_ULP_CLOSE(std::log1p(value) - value, boost::math::log1pmx(value), 1e9); } + + std::uniform_real_distribution dist2(0, 10); + + for (int n = 0; n < 100; ++n) + { + const T value (dist2(rng)); + CHECK_ULP_CLOSE(std::log1p(value) - value, boost::math::log1pmx(value), 1e9); + } +#ifndef BOOST_MATH_NO_EXCEPTIONS + CHECK_THROW(boost::math::log1pmx(T(-1.1)), std::domain_error); + CHECK_THROW(boost::math::log1pmx(T(-1.0)), std::overflow_error); +#endif } int main() diff --git a/test/test_next.cpp b/test/test_next.cpp index 8bb5f8d993..128220f5fe 100644 --- a/test/test_next.cpp +++ b/test/test_next.cpp @@ -61,6 +61,18 @@ void test_value(const T& val, const char* name) BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4); BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4); } +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_quiet_NaN) + { + BOOST_CHECK_THROW(float_distance(val, std::numeric_limits::quiet_NaN()), std::domain_error); + BOOST_CHECK_THROW(float_distance(std::numeric_limits::quiet_NaN(), val), std::domain_error); + } + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_infinity) + { + BOOST_CHECK_THROW(float_distance(val, std::numeric_limits::infinity()), std::domain_error); + BOOST_CHECK_THROW(float_distance(-std::numeric_limits::infinity(), val), std::domain_error); + } +#endif if(val > 0) { T n = val + ulp(val); @@ -177,7 +189,7 @@ void test_values(const T& val, const char* name) BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits::infinity()), -(std::numeric_limits::max)()); BOOST_CHECK_EQUAL(boost::math::float_prior(-std::numeric_limits::infinity()), -std::numeric_limits::infinity()); BOOST_CHECK_EQUAL(boost::math::float_next(std::numeric_limits::infinity()), std::numeric_limits::infinity()); - if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error) + BOOST_MATH_IF_CONSTEXPR(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error) { BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits::max)()), std::overflow_error); BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits::max)()), std::overflow_error); @@ -187,6 +199,18 @@ void test_values(const T& val, const char* name) BOOST_CHECK_EQUAL(boost::math::float_prior(-(std::numeric_limits::max)()), -std::numeric_limits::infinity()); BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits::max)()), std::numeric_limits::infinity()); } + BOOST_MATH_IF_CONSTEXPR(boost::math::policies::BOOST_MATH_DOMAIN_ERROR_POLICY == boost::math::policies::throw_on_error) + { + BOOST_MATH_CHECK_THROW(boost::math::float_advance(std::numeric_limits::infinity(), 2), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::float_advance(-std::numeric_limits::infinity(), 2), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::float_advance(std::numeric_limits::infinity(), -2), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::float_advance(-std::numeric_limits::infinity(), -2), std::domain_error); + } + else + { + BOOST_CHECK((boost::math::isnan)(boost::math::float_advance(std::numeric_limits::quiet_NaN(), 2))); + BOOST_CHECK((boost::math::isnan)(boost::math::float_advance(std::numeric_limits::quiet_NaN(), -2))); + } } BOOST_IF_CONSTEXPR(std::numeric_limits::is_specialized && (std::numeric_limits::has_quiet_NaN)) { diff --git a/test/test_next_decimal.cpp b/test/test_next_decimal.cpp index 6827a93396..29be34f998 100644 --- a/test/test_next_decimal.cpp +++ b/test/test_next_decimal.cpp @@ -54,6 +54,22 @@ void test_value(const T& val, const char* name) BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), float_next(float_next(val))), 4); BOOST_CHECK_EQUAL(float_distance(float_prior(float_next(val)), val), 0); BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0); + BOOST_CHECK_EQUAL(float_advance(val, 1), float_next(val)); + BOOST_CHECK_EQUAL(float_advance(val, -1), float_prior(val)); + +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_quiet_NaN) + { + BOOST_CHECK_THROW(float_distance(val, std::numeric_limits::quiet_NaN()), std::domain_error); + BOOST_CHECK_THROW(float_distance(std::numeric_limits::quiet_NaN(), val), std::domain_error); + } + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_infinity) + { + BOOST_CHECK_THROW(float_distance(val, std::numeric_limits::infinity()), std::domain_error); + BOOST_CHECK_THROW(float_distance(-std::numeric_limits::infinity(), val), std::domain_error); + } +#endif + if (is_normalized_value(val)) { BOOST_CHECK_EQUAL(float_prior(float_next(val)), val); @@ -197,6 +213,9 @@ void test_values(const T& val, const char* name) { BOOST_MATH_CHECK_THROW(boost::math::float_prior(std::numeric_limits::quiet_NaN()), std::domain_error); BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits::quiet_NaN()), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::float_advance(std::numeric_limits::quiet_NaN(), 3), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::float_advance(std::numeric_limits::infinity(), 3), std::domain_error); + BOOST_MATH_CHECK_THROW(boost::math::float_advance(-std::numeric_limits::infinity(), 3), std::domain_error); } } diff --git a/test/test_nonfinite_io.cpp b/test/test_nonfinite_io.cpp index 855843c715..da8d8fed0a 100644 --- a/test/test_nonfinite_io.cpp +++ b/test/test_nonfinite_io.cpp @@ -22,6 +22,8 @@ #include #include +#include "boost/math/tools/test.hpp" + namespace { // Using an anonymous namespace resolves ambiguities on platforms @@ -30,7 +32,7 @@ namespace { using namespace boost::math; using boost::math::signbit; using boost::math::changesign; -using (boost::math::isnan)(; +using boost::math::isnan; //------------------------------------------------------------------------------ // Test nonfinite_num_put and nonfinite_num_get facets by checking @@ -232,6 +234,15 @@ template void trap_test_get_nan_impl() ss.clear(); ss.str(S_("")); + ValType a3 = std::numeric_limits::quiet_NaN(); + ss << std::showpos << a3; + ValType b3; + ss >> b3; + BOOST_CHECK(ss.rdstate() == std::ios_base::failbit); + + ss.clear(); + ss.str(S_("")); + ValType a2 = std::numeric_limits::signaling_NaN(); ss << a2; ValType b2; @@ -266,7 +277,7 @@ template void trap_test_get_nan_impl() os.imbue(new_locale); os.exceptions(std::ios_base::badbit | std::ios_base::failbit); // Enable throwing exceptions. double nan = std::numeric_limits::quiet_NaN(); - BOOST_MATH_CHECK_THROW((os << nan), std::runtime_error); + BOOST_MATH_CHECK_THROW((os << nan), std::exception); // warning : in "check_trap_nan": exception std::runtime_error is expected } // BOOST_AUTO_TEST_CASE(check_trap_nan) @@ -279,7 +290,7 @@ template void trap_test_get_nan_impl() os.imbue(new_locale); os.exceptions(std::ios_base::badbit | std::ios_base::failbit); // Enable throwing exceptions. double inf = std::numeric_limits::infinity(); - BOOST_MATH_CHECK_THROW((os << inf), std::runtime_error); + BOOST_MATH_CHECK_THROW((os << inf), std::exception); // warning : in "check_trap_inf": exception std::runtime_error is expected. } // BOOST_AUTO_TEST_CASE(check_trap_nan_inf) diff --git a/test/test_prime.cpp b/test/test_prime.cpp new file mode 100644 index 0000000000..f73a9c7a08 --- /dev/null +++ b/test/test_prime.cpp @@ -0,0 +1,42 @@ +// (C) Copyright John Maddock 2025. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#define BOOST_TEST_MAIN +#include +#include +#include +#include + +// +// DESCRIPTION: +// ~~~~~~~~~~~~ +// +// This file tests the function prime. +// + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + BOOST_CHECK_EQUAL(boost::math::prime(0), 2); + BOOST_CHECK_EQUAL(boost::math::prime(49), 229); + BOOST_CHECK_EQUAL(boost::math::prime(99), 541); + BOOST_CHECK_EQUAL(boost::math::prime(499), 3571); + BOOST_CHECK_EQUAL(boost::math::prime(4999), 48611); + + BOOST_CHECK_THROW(boost::math::prime(100000), std::domain_error); + +#ifdef BOOST_MATH_HAVE_CONSTEXPR_TABLES + static_assert(boost::math::prime(0) == 2, "ooops"); + static_assert(boost::math::prime(49) == 229, "ooops"); + static_assert(boost::math::prime(99) == 541, "ooops"); + static_assert(boost::math::prime(499) == 3571, "ooops"); + static_assert(boost::math::prime(4999) == 48611, "ooops"); +#endif +} + + diff --git a/test/test_spherical_harmonic.hpp b/test/test_spherical_harmonic.hpp index 6fd700780d..d07139eccb 100644 --- a/test/test_spherical_harmonic.hpp +++ b/test/test_spherical_harmonic.hpp @@ -179,6 +179,15 @@ void test_spots(T, const char* t) BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_r(40, -15, static_cast(0.75), static_cast(2.25)), static_cast(0.2806904825045745687343492963236868973484L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_i(40, -15, static_cast(0.75), static_cast(2.25)), static_cast(0.2933918444656603582282372590387544902135L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(40, -15, static_cast(-0.75), static_cast(2.25))), static_cast(-0.2806904825045745687343492963236868973484L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(40, -15, static_cast(-0.75), static_cast(2.25))), static_cast(-0.2933918444656603582282372590387544902135L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(40, -15, static_cast(-0.75), static_cast(-2.25))), static_cast(-0.2806904825045745687343492963236868973484L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(40, -15, static_cast(-0.75), static_cast(-2.25))), static_cast(0.2933918444656603582282372590387544902135L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(40, -15, static_cast(0.75), static_cast(-2.25))), static_cast(0.2806904825045745687343492963236868973484L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(40, -15, static_cast(0.75), static_cast(-2.25))), static_cast(-0.2933918444656603582282372590387544902135L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(40, -15, static_cast(0.75), static_cast(2.25))), static_cast(0.2806904825045745687343492963236868973484L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(40, -15, static_cast(0.75), static_cast(2.25))), static_cast(0.2933918444656603582282372590387544902135L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_r(20, -14, static_cast(-0.75), static_cast(2.25)), static_cast(0.3479218186133435466692822481919867452442L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_i(20, -14, static_cast(-0.75), static_cast(2.25)), static_cast(-0.0293201066685263879566422194539567289974L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_r(20, -14, static_cast(-0.75), static_cast(-2.25)), static_cast(0.3479218186133435466692822481919867452442L), tolerance); @@ -188,6 +197,15 @@ void test_spots(T, const char* t) BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_r(20, -14, static_cast(0.75), static_cast(2.25)), static_cast(0.3479218186133435466692822481919867452442L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_i(20, -14, static_cast(0.75), static_cast(2.25)), static_cast(-0.0293201066685263879566422194539567289974L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(20, -14, static_cast(-0.75), static_cast(2.25))), static_cast(0.3479218186133435466692822481919867452442L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(20, -14, static_cast(-0.75), static_cast(2.25))), static_cast(-0.0293201066685263879566422194539567289974L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(20, -14, static_cast(-0.75), static_cast(-2.25))), static_cast(0.3479218186133435466692822481919867452442L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(20, -14, static_cast(-0.75), static_cast(-2.25))), static_cast(0.0293201066685263879566422194539567289974L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(20, -14, static_cast(0.75), static_cast(-2.25))), static_cast(0.3479218186133435466692822481919867452442L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(20, -14, static_cast(0.75), static_cast(-2.25))), static_cast(0.0293201066685263879566422194539567289974L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(real(::boost::math::spherical_harmonic(20, -14, static_cast(0.75), static_cast(2.25))), static_cast(0.3479218186133435466692822481919867452442L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(imag(::boost::math::spherical_harmonic(20, -14, static_cast(0.75), static_cast(2.25))), static_cast(-0.0293201066685263879566422194539567289974L), tolerance); + BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_r(20, 14, static_cast(-4), static_cast(2.25)), static_cast(0.5253373768014719124617844890495875474590L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_i(20, 14, static_cast(-4), static_cast(2.25)), static_cast(0.0442712905622650144694916590407495495699L), tolerance); BOOST_CHECK_CLOSE_FRACTION(::boost::math::spherical_harmonic_r(20, 14, static_cast(-4), static_cast(-2.25)), static_cast(0.5253373768014719124617844890495875474590L), tolerance); diff --git a/test/test_trigamma.hpp b/test/test_trigamma.hpp index 49b1bd5501..8bebdfd7e7 100644 --- a/test/test_trigamma.hpp +++ b/test/test_trigamma.hpp @@ -76,5 +76,10 @@ void test_trigamma(T, const char* name) {{ SC_(-1.0009765625000000000000000000000000), SC_(1.0485786453346669585098368000725210e6)}}, {{ SC_(-2.0009765625000000000000000000000000), SC_(1.0485788950907050310998538089289880e6) }}, {{ SC_(-3.0009765625000000000000000000000000), SC_(1.0485790061295134851948027406034007e6) }}, {{ SC_(-4.0009765625000000000000000000000000), SC_(1.0485790685990070793038292171104670e6) }}, {{ SC_(-5.0009765625000000000000000000000000), SC_(1.0485791085833866557487460417106589e6) }}, {{ SC_(-6.0009765625000000000000000000000000), SC_(1.0485791363521243952566116253382220e6) }}, {{ SC_(-7.0009765625000000000000000000000000), SC_(1.0485791567545946099550113256489222e6) }}, {{ SC_(-8.0009765625000000000000000000000000), SC_(1.0485791723757806110676477942302156e6) }}, {{ SC_(-9.0009765625000000000000000000000000), SC_(1.0485791847187808756018779739003157e6) }}, {{ SC_(-10.000976562500000000000000000000000), SC_(1.0485791947168280366669245397313590e6) }}, {{ SC_(-11.000976562500000000000000000000000), SC_(1.0485792029798236302523575048817360e6) }}, {{ SC_(-12.000976562500000000000000000000000), SC_(1.0485792099231379319842508274674963e6) }}, {{ SC_(-13.000976562500000000000000000000000), SC_(1.0485792158394087991015231685011609e6) }}, {{ SC_(-14.000976562500000000000000000000000), SC_(1.0485792209407379096480891892744762e6) }}, {{ SC_(-15.000976562500000000000000000000000), SC_(1.0485792253846037068979581619480639e6) }}, {{ SC_(-16.000976562500000000000000000000000), SC_(1.0485792292903769133919482794005111e6) }}, {{ SC_(-17.000976562500000000000000000000000), SC_(1.0485792327501870178663179616292787e6) }}, {{ SC_(-18.000976562500000000000000000000000), SC_(1.0485792358362719002281530732844340e6) }}, {{ SC_(-19.000976562500000000000000000000000), SC_(1.0485792386060702710649859237414384e6) }}, {{ SC_(-20.000976562500000000000000000000000), SC_(1.0485792411058261483202152741904670e6) }}, } }; do_test_trigamma(data, name, "Mathematica Data"); + + // + // Coverage: + // + BOOST_MATH_CHECK_THROW(boost::math::trigamma(T(-1)), std::domain_error); } diff --git a/test/test_ulp.cpp b/test/test_ulp.cpp new file mode 100644 index 0000000000..f57ea20613 --- /dev/null +++ b/test/test_ulp.cpp @@ -0,0 +1,42 @@ +// (C) Copyright John Maddock 2025. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#define BOOST_TEST_MAIN +#include +#include + +#include + + +template +void test() +{ + // + // Really just test our error handling: + // + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_quiet_NaN) + { + BOOST_CHECK_THROW(boost::math::ulp(std::numeric_limits::quiet_NaN()), std::domain_error); + } + BOOST_MATH_IF_CONSTEXPR(std::numeric_limits::has_infinity) + { + BOOST_CHECK_THROW(boost::math::ulp(std::numeric_limits::infinity()), std::overflow_error); + } + BOOST_CHECK_THROW(boost::math::ulp(boost::math::tools::max_value()), std::overflow_error); + + BOOST_CHECK(boost::math::ulp(static_cast(0)) != 0); +} + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test(); + test(); +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + test(); +#endif + test(); +} + diff --git a/test/test_zeta.hpp b/test/test_zeta.hpp index c46764f52b..462a96b33f 100644 --- a/test/test_zeta.hpp +++ b/test/test_zeta.hpp @@ -170,6 +170,11 @@ void test_spots(T, const char* t) BOOST_CHECK_EQUAL(::boost::math::zeta(static_cast(-10007)), std::numeric_limits::infinity()); BOOST_CHECK_EQUAL(::boost::math::zeta(static_cast(-10009)), -std::numeric_limits::infinity()); } + // + // Coverage tests: + // + BOOST_CHECK_THROW(boost::math::zeta(static_cast(1)), std::domain_error); + BOOST_CHECK_EQUAL(boost::math::zeta(-boost::math::tools::max_value()), static_cast(0)); #ifdef _MSC_VER #pragma warning(pop) #endif