summaryrefslogtreecommitdiff
path: root/boost/multiprecision/detail/functions/pow.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/multiprecision/detail/functions/pow.hpp')
-rw-r--r--boost/multiprecision/detail/functions/pow.hpp164
1 files changed, 149 insertions, 15 deletions
diff --git a/boost/multiprecision/detail/functions/pow.hpp b/boost/multiprecision/detail/functions/pow.hpp
index b244a18c8b..460658e034 100644
--- a/boost/multiprecision/detail/functions/pow.hpp
+++ b/boost/multiprecision/detail/functions/pow.hpp
@@ -208,11 +208,11 @@ void eval_exp(T& result, const T& x)
if(type == (int)FP_NAN)
{
result = x;
+ errno = EDOM;
return;
}
else if(type == (int)FP_INFINITE)
{
- result = x;
if(isneg)
result = ui_type(0u);
else
@@ -277,6 +277,17 @@ void eval_exp(T& result, const T& x)
detail::pow_imp(result, get_constant_e<T>(), ll, mpl::true_());
return;
}
+ else if(exp_series.compare(x) == 0)
+ {
+ // We have a value that has no fractional part, but is too large to fit
+ // in a long long, in this situation the code below will fail, so
+ // we're just going to assume that this will overflow:
+ if(isneg)
+ result = ui_type(0);
+ else
+ result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
+ return;
+ }
// The algorithm for exp has been taken from MPFUN.
// exp(t) = [ (1 + r + r^2/2! + r^3/3! + r^4/4! ...)^p2 ] * 2^n
@@ -326,6 +337,29 @@ void eval_log(T& result, const T& arg)
typedef typename T::exponent_type exp_type;
typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type;
typedef typename mpl::front<typename T::float_types>::type fp_type;
+ int s = eval_signbit(arg);
+ switch(eval_fpclassify(arg))
+ {
+ case FP_NAN:
+ result = arg;
+ errno = EDOM;
+ return;
+ case FP_INFINITE:
+ if(s) break;
+ result = arg;
+ return;
+ case FP_ZERO:
+ result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
+ result.negate();
+ errno = ERANGE;
+ return;
+ }
+ if(s)
+ {
+ result = std::numeric_limits<number<T> >::quiet_NaN().backend();
+ errno = EDOM;
+ return;
+ }
exp_type e;
T t;
@@ -427,19 +461,21 @@ inline void eval_pow(T& result, const T& x, const T& a)
return;
}
- if(a.compare(si_type(1)) == 0)
+ if((a.compare(si_type(1)) == 0) || (x.compare(si_type(1)) == 0))
{
result = x;
return;
}
+ if(a.compare(si_type(0)) == 0)
+ {
+ result = si_type(1);
+ return;
+ }
int type = eval_fpclassify(x);
switch(type)
{
- case FP_INFINITE:
- result = x;
- return;
case FP_ZERO:
switch(eval_fpclassify(a))
{
@@ -449,13 +485,58 @@ inline void eval_pow(T& result, const T& x, const T& a)
case FP_NAN:
result = a;
break;
+ case FP_NORMAL:
+ {
+ // Need to check for a an odd integer as a special case:
+ try
+ {
+ typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type i;
+ eval_convert_to(&i, a);
+ if(a.compare(i) == 0)
+ {
+ if(eval_signbit(a))
+ {
+ if(i & 1)
+ {
+ result = std::numeric_limits<number<T> >::infinity().backend();
+ if(eval_signbit(x))
+ result.negate();
+ errno = ERANGE;
+ }
+ else
+ {
+ result = std::numeric_limits<number<T> >::infinity().backend();
+ errno = ERANGE;
+ }
+ }
+ else if(i & 1)
+ {
+ result = x;
+ }
+ else
+ result = si_type(0);
+ return;
+ }
+ }
+ catch(const std::exception&)
+ {
+ // fallthrough..
+ }
+ }
default:
- result = x;
+ if(eval_signbit(a))
+ {
+ result = std::numeric_limits<number<T> >::infinity().backend();
+ errno = ERANGE;
+ }
+ else
+ result = x;
break;
}
return;
case FP_NAN:
result = x;
+ errno = ERANGE;
return;
default: ;
}
@@ -478,6 +559,16 @@ inline void eval_pow(T& result, const T& x, const T& a)
}
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type an;
+ typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type max_an =
+ std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::is_specialized ?
+ (std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::max)() :
+ static_cast<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>(1) << (sizeof(typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type) * CHAR_BIT - 2);
+ typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type min_an =
+ std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::is_specialized ?
+ (std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::min)() :
+ -min_an;
+
+
T fa;
#ifndef BOOST_NO_EXCEPTIONS
try
@@ -521,8 +612,33 @@ inline void eval_pow(T& result, const T& x, const T& a)
// conversion failed, just fall through, value is not an integer.
}
#endif
- if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
+ eval_floor(result, a);
+ // -1^INF is a special case in C99:
+ if((x.compare(si_type(-1)) == 0) && (eval_fpclassify(a) == FP_INFINITE))
+ {
+ result = si_type(1);
+ }
+ else if(a.compare(result) == 0)
+ {
+ // exponent is so large we have no fractional part:
+ if(x.compare(si_type(-1)) < 0)
+ {
+ result = std::numeric_limits<number<T, et_on> >::infinity().backend();
+ }
+ else
+ {
+ result = si_type(0);
+ }
+ }
+ else if(type == FP_INFINITE)
+ {
+ result = std::numeric_limits<number<T, et_on> >::infinity().backend();
+ }
+ else if(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 of pow is undefined or non-real and there is no NaN for this number type."));
@@ -534,7 +650,7 @@ inline void eval_pow(T& result, const T& x, const T& a)
eval_subtract(da, a, an);
- if((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0))
+ if((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0) && (an < max_an) && (an > min_an))
{
if(a.compare(fp_type(1e-5f)) <= 0)
{
@@ -618,14 +734,20 @@ void eval_exp2(T& result, const T& arg)
// Check for pure-integer arguments which can be either signed or unsigned.
typename boost::multiprecision::detail::canonical<typename T::exponent_type, T>::type i;
T temp;
- eval_trunc(temp, arg);
- eval_convert_to(&i, temp);
- if(arg.compare(i) == 0)
- {
- temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
- eval_ldexp(result, temp, i);
- return;
+ try {
+ eval_trunc(temp, arg);
+ eval_convert_to(&i, temp);
+ if(arg.compare(i) == 0)
+ {
+ temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
+ eval_ldexp(result, temp, i);
+ return;
+ }
}
+ catch(const boost::math::rounding_error&)
+ { /* Fallthrough */ }
+ catch(const std::runtime_error&)
+ { /* Fallthrough */ }
temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(2u);
eval_pow(result, temp, arg);
@@ -669,6 +791,8 @@ namespace detail{
switch(eval_fpclassify(x))
{
case FP_NAN:
+ errno = EDOM;
+ // fallthrough...
case FP_INFINITE:
if(p_sinh)
*p_sinh = x;
@@ -695,6 +819,8 @@ namespace detail{
T e_px, e_mx;
eval_exp(e_px, x);
eval_divide(e_mx, ui_type(1), e_px);
+ if(eval_signbit(e_mx) != eval_signbit(e_px))
+ e_mx.negate(); // Handles lack of signed zero in some types
if(p_sinh)
{
@@ -742,6 +868,14 @@ inline void eval_tanh(T& result, const T& x)
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The tanh function is only valid for floating point types.");
T c;
detail::sinhcosh(x, &result, &c);
+ if((eval_fpclassify(result) == FP_INFINITE) && (eval_fpclassify(c) == FP_INFINITE))
+ {
+ bool s = eval_signbit(result) != eval_signbit(c);
+ result = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
+ if(s)
+ result.negate();
+ return;
+ }
eval_divide(result, c);
}