diff --git a/include/boost/multiprecision/detail/default_ops.hpp b/include/boost/multiprecision/detail/default_ops.hpp index 2f6f1b5f..8c58cc8d 100644 --- a/include/boost/multiprecision/detail/default_ops.hpp +++ b/include/boost/multiprecision/detail/default_ops.hpp @@ -484,6 +484,68 @@ inline void eval_round(T& result, const T& a) } } +template +inline typename enable_if, void>::type eval_pow(T& result, const T& x, const A& a) +{ + // Note this one is resticted to float arguments since pow.hpp already has a version for + // integer powers.... + typedef typename boost::multiprecision::detail::canonical::type canonical_type; + typedef typename mpl::if_, T, canonical_type>::type cast_type; + cast_type c; + c = a; + eval_pow(result, x, c); +} + +template +inline typename enable_if, void>::type eval_pow(T& result, const A& x, const T& a) +{ + typedef typename boost::multiprecision::detail::canonical::type canonical_type; + typedef typename mpl::if_, T, canonical_type>::type cast_type; + cast_type c; + c = x; + eval_pow(result, c, a); +} + +template +inline typename enable_if, void>::type eval_fmod(T& result, const T& x, const A& a) +{ + typedef typename boost::multiprecision::detail::canonical::type canonical_type; + typedef typename mpl::if_, T, canonical_type>::type cast_type; + cast_type c; + c = a; + eval_fmod(result, x, c); +} + +template +inline typename enable_if, void>::type eval_fmod(T& result, const A& x, const T& a) +{ + typedef typename boost::multiprecision::detail::canonical::type canonical_type; + typedef typename mpl::if_, T, canonical_type>::type cast_type; + cast_type c; + c = x; + eval_fmod(result, c, a); +} + +template +inline typename enable_if, void>::type eval_atan2(T& result, const T& x, const A& a) +{ + typedef typename boost::multiprecision::detail::canonical::type canonical_type; + typedef typename mpl::if_, T, canonical_type>::type cast_type; + cast_type c; + c = a; + eval_atan2(result, x, c); +} + +template +inline typename enable_if, void>::type eval_atan2(T& result, const A& x, const T& a) +{ + typedef typename boost::multiprecision::detail::canonical::type canonical_type; + typedef typename mpl::if_, T, canonical_type>::type cast_type; + cast_type c; + c = x; + eval_atan2(result, c, a); +} + template inline typename enable_if >::type eval_gcd(T& result, const T& a, const Arithmetic& b) { @@ -861,7 +923,7 @@ inline long long llround(const mp_number& v) } #endif -#define UNARY_OP_FUNCTOR(func)\ +#define UNARY_OP_FUNCTOR(func, category)\ namespace detail{\ template \ struct BOOST_JOIN(func, _funct)\ @@ -876,11 +938,12 @@ struct BOOST_JOIN(func, _funct)\ }\ \ template \ -inline detail::mp_exp<\ +inline typename enable_if_c >::value == category,\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ - , detail::mp_exp \ -> \ + , detail::mp_exp >\ +>::type \ func(const detail::mp_exp& arg)\ {\ return detail::mp_exp<\ @@ -893,11 +956,12 @@ func(const detail::mp_exp& arg)\ );\ }\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c::value == category,\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ - , mp_number \ -> \ + , mp_number >\ +>::type \ func(const mp_number& arg)\ {\ return detail::mp_exp<\ @@ -910,7 +974,9 @@ func(const mp_number& arg)\ );\ }\ template \ -inline mp_number \ +inline typename boost::enable_if_c<\ + boost::multiprecision::number_category::value == category,\ + mp_number >::type \ func(const mp_number& arg)\ {\ mp_number result;\ @@ -919,7 +985,7 @@ func(const mp_number& arg)\ return result;\ } -#define BINARY_OP_FUNCTOR(func)\ +#define BINARY_OP_FUNCTOR(func, category)\ namespace detail{\ template \ struct BOOST_JOIN(func, _funct)\ @@ -945,12 +1011,13 @@ struct BOOST_JOIN(func, _funct)\ \ }\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c::value == category,\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , mp_number \ - , mp_number \ -> \ + , mp_number > \ +>::type \ func(const mp_number& arg, const mp_number& a)\ {\ return detail::mp_exp<\ @@ -965,12 +1032,14 @@ func(const mp_number& arg, const mp_number& a)\ );\ }\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c<\ + (number_category::value == category) && (number_category >::value == category),\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , mp_number \ - , detail::mp_exp \ -> \ + , detail::mp_exp > \ +>::type \ func(const mp_number& arg, const detail::mp_exp& a)\ {\ return detail::mp_exp<\ @@ -985,12 +1054,14 @@ func(const mp_number& arg, const detail::mp_exp& a)\ );\ }\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c<\ + (number_category::value == category) && (number_category >::value == category),\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , detail::mp_exp \ - , mp_number \ -> \ + , mp_number > \ +>::type \ func(const detail::mp_exp& arg, const mp_number& a)\ {\ return detail::mp_exp<\ @@ -1005,12 +1076,14 @@ func(const detail::mp_exp& arg, const mp_number& a)\ );\ }\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c<\ + (number_category >::value == category) && (number_category >::value == category),\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::mp_exp \ - , detail::mp_exp \ -> \ + , detail::mp_exp > \ +>::type \ func(const detail::mp_exp& arg, const detail::mp_exp& a)\ {\ return detail::mp_exp<\ @@ -1025,8 +1098,8 @@ func(const detail::mp_exp& arg, const detail::mp_exp \ -inline typename enable_if<\ - is_arithmetic,\ +inline typename enable_if_c<\ + is_arithmetic::value && (number_category::value == category),\ detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ @@ -1048,8 +1121,8 @@ func(const mp_number& arg, const Arithmetic& a)\ );\ }\ template \ -inline typename enable_if<\ - is_arithmetic,\ +inline typename enable_if_c<\ + is_arithmetic::value && (number_category >::value == category),\ detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ @@ -1071,8 +1144,8 @@ func(const detail::mp_exp& arg, const Arithmetic& a)\ );\ }\ template \ -inline typename enable_if<\ - is_arithmetic,\ +inline typename enable_if_c<\ + is_arithmetic::value && (number_category::value == category),\ detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ @@ -1094,8 +1167,8 @@ func(const Arithmetic& arg, const mp_number& a)\ );\ }\ template \ -inline typename enable_if<\ - is_arithmetic,\ +inline typename enable_if_c<\ + is_arithmetic::value && (number_category >::value == category),\ detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ @@ -1117,7 +1190,8 @@ func(const Arithmetic& arg, const detail::mp_exp& a)\ );\ }\ template \ -inline mp_number \ +inline typename enable_if_c<(number_category::value == category),\ + mp_number >::type \ func(const mp_number& arg, const mp_number& a)\ {\ mp_number result;\ @@ -1126,8 +1200,8 @@ func(const mp_number& arg, const mp_number& a)\ return result;\ }\ template \ -inline typename enable_if<\ - is_arithmetic,\ +inline typename enable_if_c<\ + is_arithmetic::value && (number_category::value == category),\ mp_number \ >::type \ func(const mp_number& arg, const Arithmetic& a)\ @@ -1139,8 +1213,8 @@ func(const mp_number& arg, const Arithmetic& a)\ return result;\ }\ template \ -inline typename enable_if<\ - is_arithmetic,\ +inline typename enable_if_c<\ + is_arithmetic::value && (number_category::value == category),\ mp_number \ >::type \ func(const Arithmetic& a, const mp_number& arg)\ @@ -1153,14 +1227,16 @@ func(const Arithmetic& a, const mp_number& arg)\ }\ -#define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2)\ +#define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c<\ + (number_category >::value == category),\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) >::type> \ , detail::mp_exp \ - , Arg2\ -> \ + , Arg2> \ +>::type \ func(const detail::mp_exp& arg, Arg2 const& a)\ {\ return detail::mp_exp<\ @@ -1174,12 +1250,14 @@ func(const detail::mp_exp& arg, Arg2 const& a)\ );\ }\ template \ -inline detail::mp_exp<\ +inline typename enable_if_c<\ + (number_category::value == category),\ + detail::mp_exp<\ detail::function\ , detail::BOOST_JOIN(func, _funct) \ , mp_number \ - , Arg2\ -> \ + , Arg2> \ +>::type \ func(const mp_number& arg, Arg2 const& a)\ {\ return detail::mp_exp<\ @@ -1194,7 +1272,9 @@ func(const mp_number& arg, Arg2 const& a)\ );\ }\ template \ -inline mp_number \ +inline typename enable_if_c<\ + (number_category::value == category),\ + mp_number >::type \ func(const mp_number& arg, Arg2 const& a)\ {\ mp_number result;\ @@ -1203,7 +1283,7 @@ func(const mp_number& arg, Arg2 const& a)\ return result;\ }\ -#define HETERO_BINARY_OP_FUNCTOR(func, Arg2)\ +#define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)\ namespace detail{\ template \ struct BOOST_JOIN(func, _funct)\ @@ -1218,44 +1298,97 @@ struct BOOST_JOIN(func, _funct)\ \ }\ \ -HETERO_BINARY_OP_FUNCTOR_B(func, Arg2) +HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) +namespace detail{ +template +struct abs_funct +{ + void operator()(Backend& result, const Backend& arg)const + { + using default_ops::eval_abs; + eval_abs(result, arg); + } +}; -UNARY_OP_FUNCTOR(abs) -UNARY_OP_FUNCTOR(fabs) -UNARY_OP_FUNCTOR(sqrt) -UNARY_OP_FUNCTOR(floor) -UNARY_OP_FUNCTOR(ceil) -UNARY_OP_FUNCTOR(trunc) -UNARY_OP_FUNCTOR(round) -UNARY_OP_FUNCTOR(exp) -UNARY_OP_FUNCTOR(log) -UNARY_OP_FUNCTOR(log10) -UNARY_OP_FUNCTOR(cos) -UNARY_OP_FUNCTOR(sin) -UNARY_OP_FUNCTOR(tan) -UNARY_OP_FUNCTOR(asin) -UNARY_OP_FUNCTOR(acos) -UNARY_OP_FUNCTOR(atan) -UNARY_OP_FUNCTOR(cosh) -UNARY_OP_FUNCTOR(sinh) -UNARY_OP_FUNCTOR(tanh) +} -HETERO_BINARY_OP_FUNCTOR(ldexp, int) -HETERO_BINARY_OP_FUNCTOR(frexp, int*) -HETERO_BINARY_OP_FUNCTOR_B(ldexp, long) -HETERO_BINARY_OP_FUNCTOR_B(frexp, long*) -HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long) -HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*) -BINARY_OP_FUNCTOR(pow) -BINARY_OP_FUNCTOR(fmod) -BINARY_OP_FUNCTOR(atan2) +template +inline detail::mp_exp< + detail::function + , detail::abs_funct >::type> + , detail::mp_exp > +abs(const detail::mp_exp& arg) +{ + return detail::mp_exp< + detail::function + , detail::abs_funct >::type> + , detail::mp_exp +> ( + detail::abs_funct >::type>() + , arg + ); +} +template +inline detail::mp_exp< + detail::function + , detail::abs_funct + , mp_number > +abs(const mp_number& arg) +{ + return detail::mp_exp< + detail::function + , detail::abs_funct + , mp_number + >( + detail::abs_funct() + , arg + ); +} +template +inline mp_number +abs(const mp_number& arg) +{ + mp_number result; + using default_ops::eval_abs; + eval_abs(result.backend(), arg.backend()); + return result; +} + +UNARY_OP_FUNCTOR(fabs, number_kind_floating_point) +UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point) +UNARY_OP_FUNCTOR(floor, number_kind_floating_point) +UNARY_OP_FUNCTOR(ceil, number_kind_floating_point) +UNARY_OP_FUNCTOR(trunc, number_kind_floating_point) +UNARY_OP_FUNCTOR(round, number_kind_floating_point) +UNARY_OP_FUNCTOR(exp, number_kind_floating_point) +UNARY_OP_FUNCTOR(log, number_kind_floating_point) +UNARY_OP_FUNCTOR(log10, number_kind_floating_point) +UNARY_OP_FUNCTOR(cos, number_kind_floating_point) +UNARY_OP_FUNCTOR(sin, number_kind_floating_point) +UNARY_OP_FUNCTOR(tan, number_kind_floating_point) +UNARY_OP_FUNCTOR(asin, number_kind_floating_point) +UNARY_OP_FUNCTOR(acos, number_kind_floating_point) +UNARY_OP_FUNCTOR(atan, number_kind_floating_point) +UNARY_OP_FUNCTOR(cosh, number_kind_floating_point) +UNARY_OP_FUNCTOR(sinh, number_kind_floating_point) +UNARY_OP_FUNCTOR(tanh, number_kind_floating_point) + +HETERO_BINARY_OP_FUNCTOR(ldexp, int, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR(frexp, int*, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long, number_kind_floating_point) +HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point) +BINARY_OP_FUNCTOR(pow, number_kind_floating_point) +BINARY_OP_FUNCTOR(fmod, number_kind_floating_point) +BINARY_OP_FUNCTOR(atan2, number_kind_floating_point) // // Integer functions: // -BINARY_OP_FUNCTOR(gcd) -BINARY_OP_FUNCTOR(lcm) +BINARY_OP_FUNCTOR(gcd, number_kind_integer) +BINARY_OP_FUNCTOR(lcm, number_kind_integer) #undef BINARY_OP_FUNCTOR diff --git a/include/boost/multiprecision/detail/functions/pow.hpp b/include/boost/multiprecision/detail/functions/pow.hpp index f9f2e37b..76312f66 100644 --- a/include/boost/multiprecision/detail/functions/pow.hpp +++ b/include/boost/multiprecision/detail/functions/pow.hpp @@ -84,11 +84,9 @@ inline void pow_imp(T& result, const T& t, const U& p, const mpl::true_&) } // namespace detail template -inline void eval_pow(T& result, const T& t, const U& p) +inline typename enable_if >::type eval_pow(T& result, const T& t, const U& p) { - BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The pow function is only valid for floating point types."); - typedef typename is_integral::type tag_type; - detail::pow_imp(result, t, p, tag_type()); + detail::pow_imp(result, t, p, mpl::true_()); } template diff --git a/include/boost/multiprecision/detail/functions/trig.hpp b/include/boost/multiprecision/detail/functions/trig.hpp index 73de53d4..d03d6cd2 100644 --- a/include/boost/multiprecision/detail/functions/trig.hpp +++ b/include/boost/multiprecision/detail/functions/trig.hpp @@ -766,7 +766,7 @@ void eval_atan2(T& result, const T& y, const T& x) eval_add(result, get_constant_pi()); } } - +/* template typename disable_if >::type eval_atan2(T& result, const T& a, const Arithmetic& b) { @@ -775,4 +775,4 @@ typename disable_if >::type eval_atan2(T& result, const T x = static_cast::type>(b); eval_atan2(result, a, x); } - +*/ diff --git a/test/mp_number_concept_check.cpp b/test/mp_number_concept_check.cpp index 07c6861a..3e051ff5 100644 --- a/test/mp_number_concept_check.cpp +++ b/test/mp_number_concept_check.cpp @@ -59,34 +59,148 @@ #include #include "libs/math/test/compile_test/instantiate.hpp" +template +void test_extra(T) +{ + T t = 1; + t = abs(t); + t = abs(t*t); + + t = fabs(t); + t = fabs(t*t); + + t = sqrt(t); + t = sqrt(t*t); + + t = floor(t); + t = floor(t*t); + + t = ceil(t); + t = ceil(t*t); + + t = trunc(t); + t = trunc(t*t); + + t = round(t); + t = round(t*t); + + t = exp(t); + t = exp(t*t); + + t = log(t); + t = log(t*t); + + t = log10(t); + t = log10(t*t); + + t = cos(t); + t = cos(t*t); + + t = sin(t); + t = sin(t*t); + + t = tan(t); + t = tan(t*t); + + t = asin(t); + t = asin(t*t); + + t = atan(t); + t = atan(t*t); + + t = acos(t); + t = acos(t*t); + + t = cosh(t); + t = cosh(t*t); + + t = sinh(t); + t = sinh(t*t); + + t = tanh(t); + t = tanh(t*t); + + double dval = 2; + t = pow(t, t); + t = pow(t, t*t); + t = pow(t, dval); + t = pow(t*t, t); + t = pow(t*t, t*t); + t = pow(t*t, dval); + t = pow(dval, t); + t = pow(dval, t*t); + + t = atan2(t, t); + t = atan2(t, t*t); + t = atan2(t, dval); + t = atan2(t*t, t); + t = atan2(t*t, t*t); + t = atan2(t*t, dval); + t = atan2(dval, t); + t = atan2(dval, t*t); + + t = fmod(t, t); + t = fmod(t, t*t); + t = fmod(t, dval); + t = fmod(t*t, t); + t = fmod(t*t, t*t); + t = fmod(t*t, dval); + t = fmod(dval, t); + t = fmod(dval, t*t); + + typedef typename T::backend_type backend_type; + typedef typename backend_type::exponent_type exp_type; + exp_type e = 0; + int i = 0; + + t = ldexp(t, i); + t = ldexp(t*t, i); + t = ldexp(t, e); + t = ldexp(t*t, e); + + t = frexp(t, &i); + t = frexp(t*t, &i); + t = frexp(t, &e); + t = frexp(t*t, &e); +} + void foo() { #ifdef TEST_BACKEND instantiate(boost::multiprecision::concepts::mp_number_float_architype()); + test_extra(boost::multiprecision::concepts::mp_number_float_architype()); #endif #ifdef TEST_MPF_50 instantiate(boost::multiprecision::mpf_float_50()); + test_extra(boost::multiprecision::mpf_float_50()); #endif #ifdef TEST_MPFR_50 instantiate(boost::multiprecision::mpfr_float_50()); + test_extra(boost::multiprecision::mpfr_float_50()); #endif #ifdef TEST_MPFR_6 instantiate(boost::multiprecision::mp_number >()); + test_extra(boost::multiprecision::mp_number >()); #endif #ifdef TEST_MPFR_15 instantiate(boost::multiprecision::mp_number >()); + test_extra(boost::multiprecision::mp_number >()); #endif #ifdef TEST_MPFR_17 instantiate(boost::multiprecision::mp_number >()); + test_extra(boost::multiprecision::mp_number >()); #endif #ifdef TEST_MPFR_30 instantiate(boost::multiprecision::mp_number >()); + test_extra(boost::multiprecision::mp_number >()); #endif #ifdef TEST_CPP_DEC_FLOAT instantiate(boost::multiprecision::cpp_dec_float_50()); + test_extra(boost::multiprecision::cpp_dec_float_50()); #endif #ifdef TEST_CPP_DEC_FLOAT_NO_ET instantiate(boost::multiprecision::mp_number, false>()); + test_extra(boost::multiprecision::mp_number, false>()); #endif }