const T& get_constant_log10() { static T result; static bool b = false; if(!b) { typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type; T ten; ten = ui_type(10u); eval_log(result, ten); } constant_initializer<T, &get_constant_log10<T> >::do_nothing(); return result; }
inline void eval_pow(T& result, const T& x, const T& a) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The pow function is only valid for floating point types."); typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type; typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type; 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; if((&result == &x) || (&result == &a)) { T t; eval_pow(t, x, a); result = t; return; } if(a.compare(si_type(1)) == 0) { result = x; return; } int type = eval_fpclassify(x); switch(type) { case FP_INFINITE: result = x; return; case FP_ZERO: result = si_type(1); return; case FP_NAN: result = x; return; default: ; } if(eval_get_sign(a) == 0) { result = si_type(1); return; } if(a.compare(si_type(-1)) < 0) { T t, da; t = a; t.negate(); eval_pow(da, x, t); eval_divide(result, si_type(1), da); return; } bool bo_a_isint = false; typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type an; T fa; try { eval_convert_to(&an, a); if(a.compare(an) == 0) { detail::pow_imp(result, x, an, mpl::true_()); return; } } catch(const std::exception&) { // conversion failed, just fall through, value is not an integer. an = (std::numeric_limits<boost::intmax_t>::max)(); } if((eval_get_sign(x) < 0) && !bo_a_isint) { result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); } T t, da; eval_subtract(da, a, an); if((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0)) { if(a.compare(fp_type(1e-5f)) <= 0) { // Series expansion for small a. eval_log(t, x); eval_multiply(t, a); hyp0F0(result, t); return; } else { // Series expansion for moderately sized x. Note that for large power of a, // the power of the integer part of a is calculated using the pown function. if(an) { da.negate(); t = si_type(1); eval_subtract(t, x); hyp1F0(result, da, t); detail::pow_imp(t, x, an, mpl::true_()); eval_multiply(result, t); } else { da = a; da.negate(); t = si_type(1); eval_subtract(t, x); hyp1F0(result, da, t); } } } else { // Series expansion for pow(x, a). Note that for large power of a, the power // of the integer part of a is calculated using the pown function. if(an) { eval_log(t, x); eval_multiply(t, da); eval_exp(result, t); detail::pow_imp(t, x, an, mpl::true_()); eval_multiply(result, t); } else { eval_log(t, x); eval_multiply(t, a); eval_exp(result, t); } } }
void eval_log10(T& result, const T& arg) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log10 function is only valid for floating point types."); eval_log(result, arg); eval_divide(result, get_constant_log10<T>()); }
inline void eval_pow(T& result, const T& x, const T& a) { BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The pow function is only valid for floating point types."); typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type; typedef typename mpl::front<typename T::float_types>::type fp_type; if((&result == &x) || (&result == &a)) { T t; eval_pow(t, x, a); result = t; return; } if(a.compare(si_type(1)) == 0) { result = x; return; } int type = eval_fpclassify(x); switch(type) { case FP_INFINITE: result = x; return; case FP_ZERO: switch(eval_fpclassify(a)) { case FP_ZERO: result = si_type(1); break; case FP_NAN: result = a; break; default: result = x; break; } return; case FP_NAN: result = x; return; default: ; } int s = eval_get_sign(a); if(s == 0) { result = si_type(1); return; } if(s < 0) { T t, da; t = a; t.negate(); eval_pow(da, x, t); eval_divide(result, si_type(1), da); return; } typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type an; T fa; #ifndef BOOST_NO_EXCEPTIONS try { #endif eval_convert_to(&an, a); if(a.compare(an) == 0) { detail::pow_imp(result, x, an, mpl::true_()); return; } #ifndef BOOST_NO_EXCEPTIONS } catch(const std::exception&) { // conversion failed, just fall through, value is not an integer. an = (std::numeric_limits<boost::intmax_t>::max)(); } #endif if((eval_get_sign(x) < 0)) { typename boost::multiprecision::detail::canonical<boost::uintmax_t, T>::type aun; #ifndef BOOST_NO_EXCEPTIONS try { #endif eval_convert_to(&aun, a); if(a.compare(aun) == 0) { fa = x; fa.negate(); eval_pow(result, fa, a); if(aun & 1u) result.negate(); return; } #ifndef BOOST_NO_EXCEPTIONS } catch(const std::exception&) { // conversion failed, just fall through, value is not an integer. } #endif if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN) result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend(); else { BOOST_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type.")); } return; } T t, da; eval_subtract(da, a, an); if((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0)) { if(a.compare(fp_type(1e-5f)) <= 0) { // Series expansion for small a. eval_log(t, x); eval_multiply(t, a); hyp0F0(result, t); return; } else { // Series expansion for moderately sized x. Note that for large power of a, // the power of the integer part of a is calculated using the pown function. if(an) { da.negate(); t = si_type(1); eval_subtract(t, x); hyp1F0(result, da, t); detail::pow_imp(t, x, an, mpl::true_()); eval_multiply(result, t); } else { da = a; da.negate(); t = si_type(1); eval_subtract(t, x); hyp1F0(result, da, t); } } } else { // Series expansion for pow(x, a). Note that for large power of a, the power // of the integer part of a is calculated using the pown function. if(an) { eval_log(t, x); eval_multiply(t, da); eval_exp(result, t); detail::pow_imp(t, x, an, mpl::true_()); eval_multiply(result, t); } else { eval_log(t, x); eval_multiply(t, a); eval_exp(result, t); } } }