// Copyright Christopher Kormanyos 2002 - 2011.
-// Copyright 2011 John Maddock. Distributed under the Boost
+// Copyright 2011 John Maddock.
// Distributed under 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)
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
//
+#include <boost/multiprecision/detail/standalone_config.hpp>
+#include <boost/multiprecision/detail/no_exceptions_support.hpp>
+#include <boost/multiprecision/detail/assert.hpp>
+
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 6326) // comparison of two constants
+#pragma warning(disable : 4127) // conditional expression is constant
#endif
template <class T>
void hyp0F1(T& result, const T& b, const T& x)
{
- typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
+ using si_type = typename boost::multiprecision::detail::canonical<std::int32_t, T>::type ;
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
// Compute the series representation of Hypergeometric0F1 taken from
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F1/06/01/01/
}
if (n >= series_limit)
- BOOST_THROW_EXCEPTION(std::runtime_error("H0F1 Failed to Converge"));
+ BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F1 Failed to Converge"));
}
template <class T, unsigned N, bool b = boost::multiprecision::detail::is_variable_precision<boost::multiprecision::number<T> >::value>
unsigned old_precision, old_arg_precision;
scoped_N_precision(T& arg)
{
- old_precision = T::default_precision();
+ old_precision = T::thread_default_precision();
old_arg_precision = arg.precision();
- T::default_precision(old_arg_precision * N);
+ T::thread_default_precision(old_arg_precision * N);
arg.precision(old_arg_precision * N);
}
~scoped_N_precision()
{
- T::default_precision(old_precision);
+ T::thread_default_precision(old_precision);
}
void reduce(T& arg)
{
// 1) To define a fixed precision type with 3 times the precision for the calculation.
// 2) To dynamically increase the precision of the variables.
//
- typedef typename boost::multiprecision::detail::transcendental_reduction_type<T>::type reduction_type;
+ using reduction_type = typename boost::multiprecision::detail::transcendental_reduction_type<T>::type;
//
// Make a copy of the arg at higher precision:
//
reduction_type reduction = get_constant_pi<reduction_type>();
eval_ldexp(reduction, reduction, -1); // divide by 2
eval_multiply(reduction, n);
+
BOOST_MATH_INSTRUMENT_CODE(big_arg.str(10, std::ios_base::scientific));
BOOST_MATH_INSTRUMENT_CODE(reduction.str(10, std::ios_base::scientific));
template <class T>
void eval_sin(T& result, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The sin function is only valid for floating point types.");
+ static_assert(number_category<T>::value == number_kind_floating_point, "The sin function is only valid for floating point types.");
BOOST_MATH_INSTRUMENT_CODE(x.str(0, std::ios_base::scientific));
if (&result == &x)
{
return;
}
- typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
- typedef typename mpl::front<typename T::float_types>::type fp_type;
+ using si_type = typename boost::multiprecision::detail::canonical<std::int32_t, T>::type ;
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
+ using fp_type = typename std::tuple_element<0, typename T::float_types>::type ;
switch (eval_fpclassify(x))
{
case FP_INFINITE:
case FP_NAN:
- if (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
{
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
errno = EDOM;
}
else
- BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
+ BOOST_MP_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
return;
case FP_ZERO:
result = x;
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific));
- BOOST_ASSERT(xx.compare(half_pi) <= 0);
- BOOST_ASSERT(xx.compare(ui_type(0)) >= 0);
+ BOOST_MP_ASSERT(xx.compare(half_pi) <= 0);
+ BOOST_MP_ASSERT(xx.compare(ui_type(0)) >= 0);
}
t = half_pi;
// divide by three identity a certain number of times.
// Here we use division by 3^9 --> (19683 = 3^9).
- static const si_type n_scale = 9;
- static const si_type n_three_pow_scale = static_cast<si_type>(19683L);
+ constexpr const si_type n_scale = 9;
+ constexpr const si_type n_three_pow_scale = static_cast<si_type>(19683L);
eval_divide(xx, n_three_pow_scale);
eval_multiply(result, xx);
// Convert back using multiple angle identity.
- for (boost::int32_t k = static_cast<boost::int32_t>(0); k < n_scale; k++)
+ for (std::int32_t k = static_cast<std::int32_t>(0); k < n_scale; k++)
{
// Rescale the cosine value using the multiple angle identity.
eval_multiply(t2, result, ui_type(3));
template <class T>
void eval_cos(T& result, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The cos function is only valid for floating point types.");
+ static_assert(number_category<T>::value == number_kind_floating_point, "The cos function is only valid for floating point types.");
if (&result == &x)
{
T temp;
return;
}
- typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
+ using si_type = typename boost::multiprecision::detail::canonical<std::int32_t, T>::type ;
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
switch (eval_fpclassify(x))
{
case FP_INFINITE:
case FP_NAN:
- if (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
{
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
errno = EDOM;
}
else
- BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
+ BOOST_MP_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
return;
case FP_ZERO:
result = ui_type(1);
{
eval_divide(t, xx, half_pi);
eval_trunc(n_pi, t);
+ //
+ // If n_pi is > 1/epsilon, then it is no longer an exact integer value
+ // but an approximation. As a result we can no longer reliably reduce
+ // xx to 0 <= xx < pi/2, nor can we tell the sign of the result as we need
+ // n_pi % 4 for that, but that will always be zero in this situation.
+ // We could use a higher precision type for n_pi, along with division at
+ // higher precision, but that's rather expensive. So for now we do not support
+ // this, and will see if anyone complains and has a legitimate use case.
+ //
+ if (n_pi.compare(get_constant_one_over_epsilon<T>()) > 0)
+ {
+ result = ui_type(1);
+ return;
+ }
BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific));
t = ui_type(4);
eval_fmod(t, n_pi, t);
}
else
{
- BOOST_ASSERT(t.compare(ui_type(3)) == 0);
+ BOOST_MP_ASSERT(t.compare(ui_type(3)) == 0);
}
if (b_go_down)
eval_increment(n_pi);
- //
- // If n_pi is > 1/epsilon, then it is no longer an exact integer value
- // but an approximation. As a result we can no longer reliably reduce
- // xx to 0 <= xx < pi/2, nor can we tell the sign of the result as we need
- // n_pi % 4 for that, but that will always be zero in this situation.
- // We could use a higher precision type for n_pi, along with division at
- // higher precision, but that's rather expensive. So for now we do not support
- // this, and will see if anyone complains and has a legitimate use case.
- //
- if (n_pi.compare(get_constant_one_over_epsilon<T>()) > 0)
- {
- result = ui_type(1);
- return;
- }
reduce_n_half_pi(xx, n_pi, b_go_down);
//
eval_subtract(xx, half_pi, xx);
eval_ldexp(half_pi, half_pi, -1);
}
- BOOST_ASSERT(xx.compare(half_pi) <= 0);
- BOOST_ASSERT(xx.compare(ui_type(0)) >= 0);
+ BOOST_MP_ASSERT(xx.compare(half_pi) <= 0);
+ BOOST_MP_ASSERT(xx.compare(ui_type(0)) >= 0);
}
else
{
template <class T>
void eval_tan(T& result, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The tan function is only valid for floating point types.");
+ static_assert(number_category<T>::value == number_kind_floating_point, "The tan function is only valid for floating point types.");
if (&result == &x)
{
T temp;
// Abramowitz and Stegun 15.1.1.
// There are no checks on input range or parameter boundaries.
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
T x_pow_n_div_n_fact(x);
T pochham_a(a);
break;
}
if (n > series_limit)
- BOOST_THROW_EXCEPTION(std::runtime_error("H2F1 failed to converge."));
+ BOOST_MP_THROW_EXCEPTION(std::runtime_error("H2F1 failed to converge."));
}
template <class T>
void eval_asin(T& result, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types.");
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
- typedef typename mpl::front<typename T::float_types>::type fp_type;
+ static_assert(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types.");
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
+ using fp_type = typename std::tuple_element<0, typename T::float_types>::type ;
if (&result == &x)
{
{
case FP_NAN:
case FP_INFINITE:
- if (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
{
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
errno = EDOM;
}
else
- BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
+ BOOST_MP_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
return;
case FP_ZERO:
result = x;
int c = xx.compare(ui_type(1));
if (c > 0)
{
- if (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
{
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
errno = EDOM;
}
else
- BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
+ BOOST_MP_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
return;
}
else if (c == 0)
return;
}
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
- typedef typename boost::multiprecision::detail::canonical<long double, T>::type guess_type;
+ using guess_type = typename boost::multiprecision::detail::canonical<long double, T>::type;
#else
- typedef fp_type guess_type;
+ using guess_type = fp_type;
#endif
// Get initial estimate using standard math function asin.
guess_type dd;
// have at least 2/3 of the digits correct on the assumption that the correction
// we've just added will finish the job...
- boost::intmax_t current_precision = eval_ilogb(result);
- boost::intmax_t target_precision = std::numeric_limits<number<T> >::is_specialized ?
+ std::intmax_t current_precision = eval_ilogb(result);
+ std::intmax_t target_precision = std::numeric_limits<number<T> >::is_specialized ?
current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3
: current_precision - 1 - (boost::multiprecision::detail::digits2<number<T> >::value() * 2) / 3;
template <class T>
inline void eval_acos(T& result, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The acos function is only valid for floating point types.");
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
+ static_assert(number_category<T>::value == number_kind_floating_point, "The acos function is only valid for floating point types.");
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
switch (eval_fpclassify(x))
{
case FP_NAN:
case FP_INFINITE:
- if (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
{
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
errno = EDOM;
}
else
- BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
+ BOOST_MP_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
return;
case FP_ZERO:
result = get_constant_pi<T>();
if (c > 0)
{
- if (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
{
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
errno = EDOM;
}
else
- BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
+ BOOST_MP_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
return;
}
else if (c == 0)
return;
}
- typedef typename mpl::front<typename T::float_types>::type fp_type;
+ using fp_type = typename std::tuple_element<0, typename T::float_types>::type;
if (xx.compare(fp_type(1e-3)) < 0)
{
}
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
- typedef typename boost::multiprecision::detail::canonical<long double, T>::type guess_type;
+ using guess_type = typename boost::multiprecision::detail::canonical<long double, T>::type;
#else
- typedef fp_type guess_type;
+ using guess_type = fp_type;
#endif
// Get initial estimate using standard math function asin.
guess_type dd;
// have at least 2/3 of the digits correct on the assumption that the correction
// we've just added will finish the job...
- boost::intmax_t current_precision = eval_ilogb(result);
- boost::intmax_t target_precision = std::numeric_limits<number<T> >::is_specialized ?
+ std::intmax_t current_precision = eval_ilogb(result);
+ std::intmax_t target_precision = std::numeric_limits<number<T> >::is_specialized ?
current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3
: current_precision - 1 - (boost::multiprecision::detail::digits2<number<T> >::value() * 2) / 3;
template <class T>
void eval_atan(T& result, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan function is only valid for floating point types.");
- typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
- typedef typename mpl::front<typename T::float_types>::type fp_type;
+ static_assert(number_category<T>::value == number_kind_floating_point, "The atan function is only valid for floating point types.");
+ using si_type = typename boost::multiprecision::detail::canonical<std::int32_t, T>::type ;
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
+ using fp_type = typename std::tuple_element<0, typename T::float_types>::type ;
switch (eval_fpclassify(x))
{
// have at least 2/3 of the digits correct on the assumption that the correction
// we've just added will finish the job...
- boost::intmax_t current_precision = eval_ilogb(result);
- boost::intmax_t target_precision = std::numeric_limits<number<T> >::is_specialized ?
+ std::intmax_t current_precision = eval_ilogb(result);
+ std::intmax_t target_precision = std::numeric_limits<number<T> >::is_specialized ?
current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3
: current_precision - 1 - (boost::multiprecision::detail::digits2<number<T> >::value() * 2) / 3;
template <class T>
void eval_atan2(T& result, const T& y, const T& x)
{
- BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan2 function is only valid for floating point types.");
+ static_assert(number_category<T>::value == number_kind_floating_point, "The atan2 function is only valid for floating point types.");
if (&result == &y)
{
T temp(y);
return;
}
- typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
+ using ui_type = typename boost::multiprecision::detail::canonical<std::uint32_t, T>::type;
switch (eval_fpclassify(y))
{
}
}
template <class T, class A>
-inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(T& result, const T& x, const A& a)
+inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_atan2(T& result, const T& x, const A& a)
{
- typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
- typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
+ using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
+ using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
cast_type c;
c = a;
eval_atan2(result, x, c);
}
template <class T, class A>
-inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(T& result, const A& x, const T& a)
+inline typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_atan2(T& result, const A& x, const T& a)
{
- typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
- typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
+ using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
+ using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
cast_type c;
c = x;
eval_atan2(result, c, a);