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

[Polygamma]

Fix real_concept compilation and runtime.
Add digits_base10 support function to policies.
This commit is contained in:
jzmaddock
2014-10-21 19:03:26 +01:00
parent 5f89e70efd
commit 4bc3b6076c
6 changed files with 108 additions and 63 deletions

View File

@@ -850,6 +850,11 @@ inline int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))
typedef mpl::bool_< std::numeric_limits<T>::is_specialized > tag_type;
return detail::digits_imp<T, Policy>(tag_type());
}
template <class T, class Policy>
inline int digits_base10(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))
{
return boost::math::policies::digits<T, Policy>() * 1000L / 301;
}
template <class Policy>
inline unsigned long get_max_series_iterations()

View File

@@ -23,7 +23,9 @@
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost { namespace math {
namespace boost { namespace math { namespace detail{
#if 0
template<class T, class Policy>
T digamma_atinfinityplus(const int, const T &x, const Policy&)
@@ -66,7 +68,7 @@
sum_base_10_exp = T(exponent_value) * 0.303F;
long int order_check = boost::math::ltrunc(term_base_10_exp) - boost::math::ltrunc(sum_base_10_exp);
long int tol = std::numeric_limits<T>::digits10;
long int tol = std::numeric_limits<T>::digits_base10;
if((two_k > 24) && (order_check < -tol))
@@ -77,6 +79,7 @@
return (log_z - one_over_2z) - sum;
}
#endif
template<class T, class Policy>
T polygamma_atinfinityplus(const int n, const T& x, const Policy& pol) // for large values of x such as for x> 400
@@ -154,9 +157,7 @@
//
if(k > policies::get_max_series_iterations<Policy>())
{
policies::raise_evaluation_error(
"polygamma<%1%>(int, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
policies::raise_evaluation_error("polygamma<%1%>(int, %1%)", "Series did not converge, closest value was %1%", sum, pol);
break;
}
}
@@ -174,7 +175,7 @@
// Use N = (0.4 * digits) + (4 * n) for target value for x:
BOOST_MATH_STD_USING
const int d4d = static_cast<boost::int32_t>(0.4F * std::numeric_limits<T>::digits10);
const int d4d = static_cast<boost::int32_t>(0.4F * policies::digits_base10<T, Policy>());
const int N4dn = static_cast<boost::int32_t>(d4d + (4 * n));
const int N = static_cast<boost::int32_t>((std::min)(N4dn, (std::numeric_limits<int>::max)()));
const int m = n;
@@ -201,7 +202,7 @@
}
template<class T, class Policy>
T polygamma_nearzero(const int n, const T& x, const Policy&)
T polygamma_nearzero(const int n, const T& x, const Policy& pol)
{
BOOST_MATH_STD_USING
// not defined for digamma
@@ -224,9 +225,10 @@
bool b_neg_term = ((n % 2) == 0);
T sum = ((!b_neg_term) ? pg_kn : -pg_kn);
for(int k = 1; k < max_iteration<T>::value; k++)
for(unsigned k = 1;; k++)
{
k_plus_n_fact *= k_plus_n_plus_one++;
k_plus_n_fact *= k_plus_n_plus_one;
k_plus_n_plus_one += 1;
one_over_k_fact /= k;
z_pow_k *= x;
@@ -234,21 +236,7 @@
const T term = (pg * z_pow_k) * one_over_k_fact;
T term_base_10_exp = ((term < 0) ? -term : term);
T sum_base_10_exp = ((sum < 0) ? -sum : sum);
int exponent_value;
static_cast<void>(frexp(term_base_10_exp, &exponent_value));
term_base_10_exp = T(exponent_value) * 0.303F;
static_cast<void>(frexp(sum_base_10_exp, &exponent_value));
sum_base_10_exp = T(exponent_value) * 0.303F;
long int order_check = boost::math::ltrunc(term_base_10_exp) - boost::math::ltrunc(sum_base_10_exp);
long int tol = std::numeric_limits<T>::digits10;
if((k > 12) && (order_check < -tol))
if(fabs(term / sum) < tools::epsilon<T>())
{
break;
}
@@ -256,6 +244,12 @@
b_neg_term = !b_neg_term;
((!b_neg_term) ? sum += term : sum -= term);
if(k > policies::get_max_series_iterations<Policy>())
{
policies::raise_evaluation_error("polygamma<%1%>(int, %1%)", "Series did not converge, closest value was %1%", sum, pol);
break;
}
}
return term0 + sum;
@@ -269,7 +263,7 @@
{
return polygamma_nearzero(n, x, pol);
}
else if(x > 0.4F * std::numeric_limits<T>::digits10 + 4 * n)
else if(x > 0.4F * policies::digits_base10<T, Policy>() + 4 * n)
{
return polygamma_atinfinityplus(n, x, pol);
}

View File

@@ -18,33 +18,57 @@
namespace boost { namespace math {
template<class T>
struct promoteftod
{
typedef T type;
};
template<>
struct promoteftod<float>
{
typedef double type;
};
template<class T, class Policy>
inline T polygamma(const int n, T x, const Policy &pol)
inline typename tools::promote_args<T>::type polygamma(const int n, T x, const Policy &pol)
{
typedef typename promoteftod<T>::type result_type;
// std::cout<<"~:"<<typeid(T).name()<<std::endl;
// std::cout<<"~:"<<typeid(result_type).name()<<std::endl;
result_type xx=result_type(x);
result_type result= boost::math::detail::polygamma_imp(n,xx,pol);
return T(result);
//
// We've found some standard library functions to misbehave if any FPU exception flags
// are set prior to their call, this code will clear those flags, then reset them
// on exit:
//
BOOST_FPU_EXCEPTION_GUARD
//
// The type of the result - the common type of T and U after
// any integer types have been promoted to double:
//
typedef typename tools::promote_args<T>::type result_type;
//
// The type used for the calculation. This may be a wider type than
// the result in order to ensure full precision:
//
typedef typename policies::evaluation<result_type, Policy>::type value_type;
//
// The type of the policy to forward to the actual implementation.
// We disable promotion of float and double as that's [possibly]
// happened already in the line above. Also reset to the default
// any policies we don't use (reduces code bloat if we're called
// multiple times with differing policies we don't actually use).
// Also normalise the type, again to reduce code bloat in case we're
// called multiple times with functionally identical policies that happen
// to be different types.
//
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
//
// Whew. Now we can make the actual call to the implementation.
// Arguments are explicitly cast to the evaluation type, and the result
// passed through checked_narrowing_cast which handles things like overflow
// according to the policy passed:
//
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::polygamma_imp(n, static_cast<value_type>(x), forwarding_policy()),
"boost::math::polygamma<%1%>(int, %1%)");
}
template<class T>
inline T polygamma(const int n, T x)
inline typename tools::promote_args<T>::type polygamma(const int n, T x)
{
return boost::math::polygamma(n,x,policies::policy<>());
return boost::math::polygamma(n, x, policies::policy<>());
}
template<class T, class Policy>

View File

@@ -603,6 +603,7 @@ run test_nc_t.cpp pch ../../test/build//boost_unit_test_framework
run test_normal.cpp pch ../../test/build//boost_unit_test_framework ;
run test_owens_t.cpp ../../test/build//boost_unit_test_framework ;
run test_pareto.cpp ../../test/build//boost_unit_test_framework ;
run test_polygamma.cpp test_instances//test_instances pch_light ../../test/build//boost_unit_test_framework ;
run test_poisson.cpp ../../test/build//boost_unit_test_framework
: # command line
: # input files

View File

@@ -5,7 +5,7 @@
#include <pch_light.hpp>
#include "test_polygamma.hpp"
//#include <boost/cstdfloat.hpp>
void expected_results()
{
@@ -17,16 +17,30 @@ void expected_results()
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
if(boost::math::policies::digits<double, boost::math::policies::policy<> >() == boost::math::policies::digits<long double, boost::math::policies::policy<> >())
{
largest_type = "(long\\s+)?double";
largest_type = "(long\\s+)?double|real_concept";
}
else
{
largest_type = "long double";
largest_type = "long double|real_concept";
}
#else
largest_type = "(long\\s+)?double";
largest_type = "(long\\s+)?double|real_concept";
#endif
add_expected_result(
".*", // compiler
".*", // stdlib
".*", // platform
largest_type, // test type(s)
".*large arguments", // test data group
".*", 400, 200); // test function
add_expected_result(
".*", // compiler
".*", // stdlib
".*", // platform
largest_type, // test type(s)
".*", // test data group
".*", 20, 10); // test function
//
// Finish off by printing out the compiler/stdlib/platform names,
// we do this to make it easier to mark up expected error rates.
@@ -40,11 +54,14 @@ BOOST_AUTO_TEST_CASE( test_main )
expected_results();
BOOST_MATH_CONTROL_FP;
//test_polygamma(0.0F, "float");
test_polygamma(0.0F, "float");
test_polygamma(0.0, "double");
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
test_polygamma(0.0L, "long double");
//test_polygamma(boost::math::concepts::real_concept(0.1), "real_concept");
test_polygamma(boost::math::concepts::real_concept(0.1), "real_concept");
#endif
#ifdef BOOST_FLOAT128_C
//test_polygamma(BOOST_FLOAT128_C(0.0), "float128_t");
#endif
}

File diff suppressed because one or more lines are too long