Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Copyright 2011 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_MATH_BIG_NUM_DEF_OPS Chris@16: #define BOOST_MATH_BIG_NUM_DEF_OPS Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifndef INSTRUMENT_BACKEND Chris@16: #ifndef BOOST_MP_INSTRUMENT Chris@16: #define INSTRUMENT_BACKEND(x) Chris@16: #else Chris@16: #define INSTRUMENT_BACKEND(x)\ Chris@16: std::cout << BOOST_STRINGIZE(x) << " = " << x.str(0, std::ios_base::scientific) << std::endl; Chris@16: #endif Chris@16: #endif Chris@16: Chris@16: Chris@16: namespace boost{ namespace multiprecision{ namespace default_ops{ Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: // warning C4127: conditional expression is constant Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4127) Chris@16: #endif Chris@16: // Chris@16: // Default versions of mixed arithmetic, these just construct a temporary Chris@16: // from the arithmetic value and then do the arithmetic on that, two versions Chris@16: // of each depending on whether the backend can be directly constructed from type V. Chris@16: // Chris@16: // Note that we have to provide *all* the template parameters to class number when used in Chris@16: // enable_if as MSVC-10 won't compile the code if we rely on a computed-default parameter. Chris@16: // Since the result of the test doesn't depend on whether expression templates are on or off Chris@16: // we just use et_on everywhere. We could use a BOOST_WORKAROUND but that just obfuscates the Chris@16: // code even more.... Chris@16: // Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value >::type Chris@16: eval_add(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_add(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value >::type Chris@16: eval_add(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_add(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_subtract(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_subtract(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_subtract(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_subtract(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_multiply(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_multiply(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_multiply(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_multiply(result, t); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_multiply(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline typename disable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v) Chris@16: { Chris@16: T z; Chris@16: eval_multiply(z, u, v); Chris@16: eval_add(t, z); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_multiply_add(t, v, u); Chris@16: } Chris@16: template Chris@16: inline typename disable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v) Chris@16: { Chris@16: T z; Chris@16: eval_multiply(z, u, v); Chris@16: eval_subtract(t, z); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_multiply_subtract(t, v, u); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_divide(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_divide(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_divide(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_divide(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_modulus(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_modulus(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value&& is_convertible::value>::type Chris@16: eval_modulus(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_modulus(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_bitwise_and(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_bitwise_and(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_bitwise_and(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_bitwise_and(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_bitwise_or(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_bitwise_or(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_bitwise_or(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_bitwise_or(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_bitwise_xor(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_bitwise_xor(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_bitwise_xor(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_bitwise_xor(result, t); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type Chris@16: eval_complement(T& result, V const& v) Chris@16: { Chris@16: T t; Chris@16: t = v; Chris@16: eval_complement(result, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type Chris@16: eval_complement(T& result, V const& v) Chris@16: { Chris@16: T t(v); Chris@16: eval_complement(result, t); Chris@16: } Chris@16: Chris@16: // Chris@16: // Default versions of 3-arg arithmetic functions, these mostly just forward to the 2 arg versions: Chris@16: // Chris@16: template Chris@16: void eval_add(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_add_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &v) Chris@16: { Chris@16: eval_add(t, u); Chris@16: } Chris@16: else if(&t == &u) Chris@16: { Chris@16: eval_add(t, v); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_add(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_add(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_add_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_add(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value>::type eval_add_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: eval_add(t, v, u); Chris@16: } Chris@16: template Chris@16: inline void eval_add_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: eval_add(t, u); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_add(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_add(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_add_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_subtract(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_subtract_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if((&t == &v) && is_signed_number::value) Chris@16: { Chris@16: eval_subtract(t, u); Chris@16: t.negate(); Chris@16: } Chris@16: else if(&t == &u) Chris@16: { Chris@16: eval_subtract(t, v); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_subtract(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_subtract(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_subtract_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_subtract(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_signed_number::value>::type eval_subtract_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: eval_subtract(t, v, u); Chris@16: t.negate(); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_unsigned_number::value>::type eval_subtract_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: T temp(u); Chris@16: eval_subtract(t, temp, v); Chris@16: } Chris@16: template Chris@16: inline void eval_subtract_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: eval_subtract(t, u); Chris@16: t.negate(); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_subtract(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_subtract(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_subtract_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_multiply_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &v) Chris@16: { Chris@16: eval_multiply(t, u); Chris@16: } Chris@16: else if(&t == &u) Chris@16: { Chris@16: eval_multiply(t, v); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_multiply(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_multiply(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_multiply_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_multiply(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value>::type eval_multiply_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: eval_multiply(t, v, u); Chris@16: } Chris@16: template Chris@16: inline void eval_multiply_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: eval_multiply(t, u); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_multiply(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_multiply(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_multiply_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename disable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) Chris@16: { Chris@16: if((void*)&x == (void*)&t) Chris@16: { Chris@16: T z; Chris@16: z = x; Chris@16: eval_multiply_add(t, u, v, z); Chris@16: } Chris@16: else Chris@16: { Chris@16: eval_multiply(t, u, v); Chris@16: eval_add(t, x); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c::value && is_same::value>::type eval_multiply_add(T& t, const U& u, const V& v, const X& x) Chris@16: { Chris@16: eval_multiply_add(t, v, u, x); Chris@16: } Chris@16: template Chris@16: inline typename disable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x) Chris@16: { Chris@16: if((void*)&x == (void*)&t) Chris@16: { Chris@16: T z; Chris@16: z = x; Chris@16: eval_multiply_subtract(t, u, v, z); Chris@16: } Chris@16: else Chris@16: { Chris@16: eval_multiply(t, u, v); Chris@16: eval_subtract(t, x); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c::value && is_same::value>::type eval_multiply_subtract(T& t, const U& u, const V& v, const X& x) Chris@16: { Chris@16: eval_multiply_subtract(t, v, u, x); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_divide(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_divide_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &u) Chris@16: eval_divide(t, v); Chris@16: else if(&t == &v) Chris@16: { Chris@16: T temp; Chris@16: eval_divide(temp, u, v); Chris@16: temp.swap(t); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_divide(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_divide(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_divide_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_divide(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: T uu; Chris@16: uu = u; Chris@16: eval_divide(t, uu, v); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_divide_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: T uu(u); Chris@16: eval_divide(t, uu, v); Chris@16: } Chris@16: template Chris@16: inline void eval_divide_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: T temp(u); Chris@16: eval_divide(temp, v); Chris@16: t = temp; Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_divide(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_divide(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_divide_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_modulus(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_modulus_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &u) Chris@16: eval_modulus(t, v); Chris@16: else if(&t == &v) Chris@16: { Chris@16: T temp; Chris@16: eval_modulus(temp, u, v); Chris@16: temp.swap(t); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_modulus(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_modulus(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_modulus_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_modulus(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: T uu; Chris@16: uu = u; Chris@16: eval_modulus(t, uu, v); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_modulus_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: T uu(u); Chris@16: eval_modulus(t, uu, v); Chris@16: } Chris@16: template Chris@16: inline void eval_modulus_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: T temp(u); Chris@16: eval_modulus(temp, v); Chris@16: t = temp; Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_modulus(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_modulus(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_modulus_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_bitwise_and(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_bitwise_and_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &v) Chris@16: { Chris@16: eval_bitwise_and(t, u); Chris@16: } Chris@16: else if(&t == &u) Chris@16: { Chris@16: eval_bitwise_and(t, v); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_bitwise_and(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_bitwise_and(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_and_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_bitwise_and(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value>::type eval_bitwise_and_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: eval_bitwise_and(t, v, u); Chris@16: } Chris@16: template Chris@16: inline void eval_bitwise_and_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: eval_bitwise_and(t, u); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_bitwise_and(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_bitwise_and(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_bitwise_and_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_bitwise_or(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_bitwise_or_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &v) Chris@16: { Chris@16: eval_bitwise_or(t, u); Chris@16: } Chris@16: else if(&t == &u) Chris@16: { Chris@16: eval_bitwise_or(t, v); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_bitwise_or(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_bitwise_or(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_or_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_bitwise_or(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value>::type eval_bitwise_or_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: eval_bitwise_or(t, v, u); Chris@16: } Chris@16: template Chris@16: inline void eval_bitwise_or_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: eval_bitwise_or(t, u); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_bitwise_or(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_bitwise_or(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_bitwise_or_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_bitwise_xor(T& t, const U& u, const V& v); Chris@16: Chris@16: template Chris@16: inline void eval_bitwise_xor_default(T& t, const T& u, const T& v) Chris@16: { Chris@16: if(&t == &v) Chris@16: { Chris@16: eval_bitwise_xor(t, u); Chris@16: } Chris@16: else if(&t == &u) Chris@16: { Chris@16: eval_bitwise_xor(t, v); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_bitwise_xor(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv; Chris@16: vv = v; Chris@16: eval_bitwise_xor(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && is_convertible::value>::type eval_bitwise_xor_default(T& t, const T& u, const U& v) Chris@16: { Chris@16: T vv(v); Chris@16: eval_bitwise_xor(t, u, vv); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value>::type eval_bitwise_xor_default(T& t, const U& u, const T& v) Chris@16: { Chris@16: eval_bitwise_xor(t, v, u); Chris@16: } Chris@16: template Chris@16: inline void eval_bitwise_xor_default(T& t, const U& u, const V& v) Chris@16: { Chris@16: if(is_same::value && ((void*)&t == (void*)&v)) Chris@16: { Chris@16: eval_bitwise_xor(t, u); Chris@16: } Chris@16: else Chris@16: { Chris@16: t = u; Chris@16: eval_bitwise_xor(t, v); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void eval_bitwise_xor(T& t, const U& u, const V& v) Chris@16: { Chris@16: eval_bitwise_xor_default(t, u, v); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_increment(T& val) Chris@16: { Chris@16: typedef typename mpl::front::type ui_type; Chris@16: eval_add(val, static_cast(1u)); Chris@16: } Chris@16: template Chris@16: inline void eval_decrement(T& val) Chris@16: { Chris@16: typedef typename mpl::front::type ui_type; Chris@16: eval_subtract(val, static_cast(1u)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_left_shift(T& result, const T& arg, const V val) Chris@16: { Chris@16: result = arg; Chris@16: eval_left_shift(result, val); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_right_shift(T& result, const T& arg, const V val) Chris@16: { Chris@16: result = arg; Chris@16: eval_right_shift(result, val); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool eval_is_zero(const T& val) Chris@16: { Chris@16: typedef typename mpl::front::type ui_type; Chris@16: return val.compare(static_cast(0)) == 0; Chris@16: } Chris@16: template Chris@16: inline int eval_get_sign(const T& val) Chris@16: { Chris@16: typedef typename mpl::front::type ui_type; Chris@16: return val.compare(static_cast(0)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void assign_components_imp(T& result, const V& v1, const V& v2, const mpl::int_&) Chris@16: { Chris@16: result = v1; Chris@16: T t; Chris@16: t = v2; Chris@16: eval_divide(result, t); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void assign_components(T& result, const V& v1, const V& v2) Chris@16: { Chris@16: return assign_components_imp(result, v1, v2, typename number_category::type()); Chris@16: } Chris@16: Chris@16: template Chris@16: struct has_enough_bits Chris@16: { Chris@16: template Chris@16: struct type : public mpl::and_ >, mpl::bool_::digits >= b> >{}; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct terminal Chris@16: { Chris@16: terminal(const R& v) : value(v){} Chris@16: terminal(){} Chris@16: terminal& operator = (R val) { value = val; } Chris@16: R value; Chris@16: operator R()const { return value; } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct calculate_next_larger_type Chris@16: { Chris@16: // Find which list we're looking through: Chris@16: typedef typename mpl::if_< Chris@16: is_signed, Chris@16: typename B::signed_types, Chris@16: typename mpl::if_< Chris@16: is_unsigned, Chris@16: typename B::unsigned_types, Chris@16: typename B::float_types Chris@16: >::type Chris@16: >::type list_type; Chris@16: // A predicate to find a type with enough bits: Chris@16: typedef typename has_enough_bits::digits>::template type pred_type; Chris@16: // See if the last type is in the list, if so we have to start after this: Chris@16: typedef typename mpl::find_if< Chris@16: list_type, Chris@16: is_same Chris@16: >::type start_last; Chris@16: // Where we're starting from, either the start of the sequence or the last type found: Chris@16: typedef typename mpl::if_::type>, typename mpl::begin::type, start_last>::type start_seq; Chris@16: // The range we're searching: Chris@16: typedef mpl::iterator_range::type> range; Chris@16: // Find the next type: Chris@16: typedef typename mpl::find_if< Chris@16: range, Chris@16: pred_type Chris@16: >::type iter_type; Chris@16: // Either the next type, or a "terminal" to indicate we've run out of types to search: Chris@16: typedef typename mpl::eval_if< Chris@16: is_same::type, iter_type>, Chris@16: mpl::identity >, Chris@16: mpl::deref Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline bool check_in_range(const T& t) Chris@16: { Chris@16: // Can t fit in an R? Chris@16: if(std::numeric_limits::is_specialized && std::numeric_limits::is_bounded && (t > (std::numeric_limits::max)())) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool check_in_range(const terminal&) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_convert_to(R* result, const B& backend) Chris@16: { Chris@16: typedef typename calculate_next_larger_type::type next_type; Chris@16: next_type n; Chris@16: eval_convert_to(&n, backend); Chris@16: if(check_in_range(n)) Chris@16: { Chris@16: *result = (std::numeric_limits::max)(); Chris@16: } Chris@16: else Chris@16: *result = static_cast(n); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_convert_to(terminal* result, const B& backend) Chris@16: { Chris@16: // Chris@16: // We ran out of types to try for the conversion, try Chris@16: // a lexical_cast and hope for the best: Chris@16: // Chris@16: result->value = boost::lexical_cast(backend.str(0, std::ios_base::fmtflags(0))); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_convert_to(std::string* result, const B& backend) Chris@16: { Chris@16: *result = backend.str(0, std::ios_base::fmtflags(0)); Chris@16: } Chris@16: // Chris@16: // Functions: Chris@16: // Chris@16: template Chris@16: void eval_abs(T& result, const T& arg) Chris@16: { Chris@16: typedef typename T::signed_types type_list; Chris@16: typedef typename mpl::front::type front; Chris@16: result = arg; Chris@16: if(arg.compare(front(0)) < 0) Chris@16: result.negate(); Chris@16: } Chris@16: template Chris@16: void eval_fabs(T& result, const T& arg) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The fabs function is only valid for floating point types."); Chris@16: typedef typename T::signed_types type_list; Chris@16: typedef typename mpl::front::type front; Chris@16: result = arg; Chris@16: if(arg.compare(front(0)) < 0) Chris@16: result.negate(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline int eval_fpclassify(const Backend& arg) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The fpclassify function is only valid for floating point types."); Chris@16: return eval_is_zero(arg) ? FP_ZERO : FP_NORMAL; Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_fmod(T& result, const T& a, const T& b) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The fmod function is only valid for floating point types."); Chris@16: if((&result == &a) || (&result == &b)) Chris@16: { Chris@16: T temp; Chris@16: eval_fmod(temp, a, b); Chris@16: result = temp; Chris@16: return; Chris@16: } Chris@16: T n; Chris@16: eval_divide(result, a, b); Chris@16: if(eval_get_sign(a) < 0) Chris@16: eval_ceil(n, result); Chris@16: else Chris@16: eval_floor(n, result); Chris@16: eval_multiply(n, b); Chris@16: eval_subtract(result, a, n); Chris@16: } Chris@16: template Chris@16: inline typename enable_if, void>::type eval_fmod(T& result, const T& x, const A& a) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type canonical_type; Chris@16: typedef typename mpl::if_, T, canonical_type>::type cast_type; Chris@16: cast_type c; Chris@16: c = a; Chris@16: eval_fmod(result, x, c); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if, void>::type eval_fmod(T& result, const A& x, const T& a) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type canonical_type; Chris@16: typedef typename mpl::if_, T, canonical_type>::type cast_type; Chris@16: cast_type c; Chris@16: c = x; Chris@16: eval_fmod(result, c, a); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_trunc(T& result, const T& a) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The trunc function is only valid for floating point types."); Chris@16: int c = eval_fpclassify(a); Chris@101: if(c == (int)FP_NAN || c == (int)FP_INFINITE) Chris@16: { Chris@16: result = boost::math::policies::raise_rounding_error("boost::multiprecision::trunc<%1%>(%1%)", 0, number(a), number(a), boost::math::policies::policy<>()).backend(); Chris@16: return; Chris@16: } Chris@16: if(eval_get_sign(a) < 0) Chris@16: eval_ceil(result, a); Chris@16: else Chris@16: eval_floor(result, a); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_round(T& result, const T& a) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_floating_point, "The round function is only valid for floating point types."); Chris@16: typedef typename boost::multiprecision::detail::canonical::type fp_type; Chris@16: int c = eval_fpclassify(a); Chris@101: if((c == (int)FP_NAN) || (c == (int)FP_INFINITE)) Chris@16: { Chris@16: result = boost::math::policies::raise_rounding_error("boost::multiprecision::round<%1%>(%1%)", 0, number(a), number(a), boost::math::policies::policy<>()).backend(); Chris@16: return; Chris@16: } Chris@16: if(eval_get_sign(a) < 0) Chris@16: { Chris@16: eval_subtract(result, a, fp_type(0.5f)); Chris@16: eval_ceil(result, result); Chris@16: } Chris@16: else Chris@16: { Chris@16: eval_add(result, a, fp_type(0.5f)); Chris@16: eval_floor(result, result); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_lcm(B& result, const B& a, const B& b); Chris@16: template Chris@16: void eval_gcd(B& result, const B& a, const B& b); Chris@16: Chris@16: template Chris@16: inline typename enable_if >::type eval_gcd(T& result, const T& a, const Arithmetic& b) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type si_type; Chris@16: using default_ops::eval_gcd; Chris@16: T t; Chris@16: t = static_cast(b); Chris@16: eval_gcd(result, a, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if >::type eval_gcd(T& result, const Arithmetic& a, const T& b) Chris@16: { Chris@16: eval_gcd(result, b, a); Chris@16: } Chris@16: template Chris@16: inline typename enable_if >::type eval_lcm(T& result, const T& a, const Arithmetic& b) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type si_type; Chris@16: using default_ops::eval_lcm; Chris@16: T t; Chris@16: t = static_cast(b); Chris@16: eval_lcm(result, a, t); Chris@16: } Chris@16: template Chris@16: inline typename enable_if >::type eval_lcm(T& result, const Arithmetic& a, const T& b) Chris@16: { Chris@16: eval_lcm(result, b, a); Chris@16: } Chris@16: Chris@16: template Chris@16: inline unsigned eval_lsb(const T& val) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type ui_type; Chris@16: int c = eval_get_sign(val); Chris@16: if(c == 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); Chris@16: } Chris@16: if(c < 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); Chris@16: } Chris@16: unsigned result = 0; Chris@16: T mask, t; Chris@16: mask = ui_type(1); Chris@16: do Chris@16: { Chris@16: eval_bitwise_and(t, mask, val); Chris@16: ++result; Chris@16: eval_left_shift(mask, 1); Chris@16: } Chris@16: while(eval_is_zero(t)); Chris@16: Chris@16: return --result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline int eval_msb(const T& val) Chris@16: { Chris@16: int c = eval_get_sign(val); Chris@16: if(c == 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); Chris@16: } Chris@16: if(c < 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); Chris@16: } Chris@16: // Chris@16: // This implementation is really really rubbish - it does Chris@16: // a linear scan for the most-significant-bit. We should really Chris@16: // do a binary search, but as none of our backends actually needs Chris@16: // this implementation, we'll leave it for now. In fact for most Chris@16: // backends it's likely that there will always be a more efficient Chris@16: // native implementation possible. Chris@16: // Chris@16: unsigned result = 0; Chris@16: T t(val); Chris@16: while(!eval_is_zero(t)) Chris@16: { Chris@16: eval_right_shift(t, 1); Chris@16: ++result; Chris@16: } Chris@16: return --result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool eval_bit_test(const T& val, unsigned index) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type ui_type; Chris@16: T mask, t; Chris@16: mask = ui_type(1); Chris@16: eval_left_shift(mask, index); Chris@16: eval_bitwise_and(t, mask, val); Chris@16: return !eval_is_zero(t); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_bit_set(T& val, unsigned index) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type ui_type; Chris@16: T mask; Chris@16: mask = ui_type(1); Chris@16: eval_left_shift(mask, index); Chris@16: eval_bitwise_or(val, mask); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_bit_flip(T& val, unsigned index) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type ui_type; Chris@16: T mask; Chris@16: mask = ui_type(1); Chris@16: eval_left_shift(mask, index); Chris@16: eval_bitwise_xor(val, mask); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void eval_bit_unset(T& val, unsigned index) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type ui_type; Chris@16: T mask, t; Chris@16: mask = ui_type(1); Chris@16: eval_left_shift(mask, index); Chris@16: eval_bitwise_and(t, mask, val); Chris@16: if(!eval_is_zero(t)) Chris@16: eval_bitwise_xor(val, mask); Chris@16: } Chris@16: Chris@16: template Chris@16: void eval_integer_sqrt(B& s, B& r, const B& x) Chris@16: { Chris@16: // Chris@16: // This is slow bit-by-bit integer square root, see for example Chris@16: // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29 Chris@16: // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf Chris@16: // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented Chris@16: // at some point. Chris@16: // Chris@16: typedef typename boost::multiprecision::detail::canonical::type ui_type; Chris@16: Chris@16: s = ui_type(0u); Chris@16: if(eval_get_sign(x) == 0) Chris@16: { Chris@16: r = ui_type(0u); Chris@16: return; Chris@16: } Chris@16: int g = eval_msb(x); Chris@16: if(g == 0) Chris@16: { Chris@16: r = ui_type(1); Chris@16: return; Chris@16: } Chris@16: Chris@16: B t; Chris@16: r = x; Chris@16: g /= 2; Chris@16: int org_g = g; Chris@16: eval_bit_set(s, g); Chris@16: eval_bit_set(t, 2 * g); Chris@16: eval_subtract(r, x, t); Chris@16: --g; Chris@16: if(eval_get_sign(r) == 0) Chris@16: return; Chris@16: int msbr = eval_msb(r); Chris@16: do Chris@16: { Chris@16: if(msbr >= org_g + g + 1) Chris@16: { Chris@16: t = s; Chris@16: eval_left_shift(t, g + 1); Chris@16: eval_bit_set(t, 2 * g); Chris@16: if(t.compare(r) <= 0) Chris@16: { Chris@16: eval_bit_set(s, g); Chris@16: eval_subtract(r, t); Chris@16: if(eval_get_sign(r) == 0) Chris@16: return; Chris@16: msbr = eval_msb(r); Chris@16: } Chris@16: } Chris@16: --g; Chris@16: } Chris@16: while(g >= 0); Chris@16: } Chris@16: Chris@16: // Chris@16: // These have to implemented by the backend, declared here so that our macro generated code compiles OK. Chris@16: // Chris@16: template Chris@16: typename enable_if_c::type eval_floor(); Chris@16: template Chris@16: typename enable_if_c::type eval_ceil(); Chris@16: template Chris@16: typename enable_if_c::type eval_trunc(); Chris@16: template Chris@16: typename enable_if_c::type eval_sqrt(); Chris@16: template Chris@16: typename enable_if_c::type eval_ldexp(); Chris@16: template Chris@16: typename enable_if_c::type eval_frexp(); Chris@101: Chris@101: // Chris@101: // eval_logb and eval_scalbn simply assume base 2 and forward to Chris@101: // eval_ldexp and eval_frexp: Chris@101: // Chris@101: template Chris@101: inline typename B::exponent_type eval_ilogb(const B& val) Chris@101: { Chris@101: BOOST_STATIC_ASSERT_MSG(!std::numeric_limits >::is_specialized || (std::numeric_limits >::radix == 2), "The default implementation of ilogb requires a base 2 number type"); Chris@101: typename B::exponent_type e; Chris@101: B result; Chris@101: eval_frexp(result, val, &e); Chris@101: return e - 1; Chris@101: } Chris@101: template Chris@101: inline void eval_logb(B& result, const B& val) Chris@101: { Chris@101: typedef typename boost::mpl::if_c::value, long long, boost::intmax_t>::type max_t; Chris@101: result = static_cast(eval_ilogb(val)); Chris@101: } Chris@101: template Chris@101: inline void eval_scalbn(B& result, const B& val, A e) Chris@101: { Chris@101: BOOST_STATIC_ASSERT_MSG(!std::numeric_limits >::is_specialized || (std::numeric_limits >::radix == 2), "The default implementation of scalbn requires a base 2 number type"); Chris@101: eval_ldexp(result, val, static_cast(e)); Chris@101: } Chris@16: // Chris@16: // These functions are implemented in separate files, but expanded inline here, Chris@16: // DO NOT CHANGE THE ORDER OF THESE INCLUDES: Chris@16: // Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: } Chris@16: Chris@16: } // namespace multiprecision Chris@16: namespace math{ Chris@16: // Chris@16: // Default versions of floating point classification routines: Chris@16: // Chris@16: template Chris@16: inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) Chris@16: { Chris@16: using multiprecision::default_ops::eval_fpclassify; Chris@16: return eval_fpclassify(arg.backend()); Chris@16: } Chris@16: template Chris@16: inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) Chris@16: { Chris@16: typedef typename multiprecision::detail::expression::result_type value_type; Chris@16: return (fpclassify)(value_type(arg)); Chris@16: } Chris@16: template Chris@16: inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) Chris@16: { Chris@16: int v = (fpclassify)(arg); Chris@101: return (v != (int)FP_INFINITE) && (v != (int)FP_NAN); Chris@16: } Chris@16: template Chris@16: inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) Chris@16: { Chris@16: typedef typename multiprecision::detail::expression::result_type value_type; Chris@16: return (isfinite)(value_type(arg)); Chris@16: } Chris@16: template Chris@16: inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) Chris@16: { Chris@101: return (fpclassify)(arg) == (int)FP_NAN; Chris@16: } Chris@16: template Chris@16: inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) Chris@16: { Chris@16: typedef typename multiprecision::detail::expression::result_type value_type; Chris@16: return (isnan)(value_type(arg)); Chris@16: } Chris@16: template Chris@16: inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) Chris@16: { Chris@101: return (fpclassify)(arg) == (int)FP_INFINITE; Chris@16: } Chris@16: template Chris@16: inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) Chris@16: { Chris@16: typedef typename multiprecision::detail::expression::result_type value_type; Chris@16: return (isinf)(value_type(arg)); Chris@16: } Chris@16: template Chris@16: inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number& arg) Chris@16: { Chris@101: return (fpclassify)(arg) == (int)FP_NORMAL; Chris@16: } Chris@16: template Chris@16: inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression& arg) Chris@16: { Chris@16: typedef typename multiprecision::detail::expression::result_type value_type; Chris@16: return (isnormal)(value_type(arg)); Chris@16: } Chris@16: Chris@16: } // namespace math Chris@16: namespace multiprecision{ Chris@16: Chris@16: template Chris@16: inline number& add(number& result, const number& a, const number& b) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); Chris@16: BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); Chris@16: using default_ops::eval_add; Chris@16: eval_add(result.backend(), a.backend(), b.backend()); Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline number& subtract(number& result, const number& a, const number& b) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); Chris@16: BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); Chris@16: using default_ops::eval_subtract; Chris@16: eval_subtract(result.backend(), a.backend(), b.backend()); Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline number& multiply(number& result, const number& a, const number& b) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); Chris@16: BOOST_STATIC_ASSERT_MSG((is_convertible::value), "No conversion to the target of a mixed precision addition exists"); Chris@16: using default_ops::eval_multiply; Chris@16: eval_multiply(result.backend(), a.backend(), b.backend()); Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value, number&>::type Chris@16: add(number& result, const I& a, const I& b) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: typedef typename detail::canonical::type canonical_type; Chris@16: eval_add(result.backend(), static_cast(a), static_cast(b)); Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value, number&>::type Chris@16: subtract(number& result, const I& a, const I& b) Chris@16: { Chris@16: using default_ops::eval_subtract; Chris@16: typedef typename detail::canonical::type canonical_type; Chris@16: eval_subtract(result.backend(), static_cast(a), static_cast(b)); Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value, number&>::type Chris@16: multiply(number& result, const I& a, const I& b) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: typedef typename detail::canonical::type canonical_type; Chris@16: eval_multiply(result.backend(), static_cast(a), static_cast(b)); Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename detail::expression::result_type trunc(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: return BOOST_MP_MOVE(trunc(number_type(v), pol)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline number trunc(const number& v, const Policy&) Chris@16: { Chris@16: using default_ops::eval_trunc; Chris@16: number result; Chris@16: eval_trunc(result.backend(), v.backend()); Chris@16: return BOOST_MP_MOVE(result); Chris@16: } Chris@16: Chris@16: template Chris@16: inline int itrunc(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: number_type r = trunc(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, number_type(v), 0, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline int itrunc(const detail::expression& v) Chris@16: { Chris@16: return itrunc(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline int itrunc(const number& v, const Policy& pol) Chris@16: { Chris@16: number r = trunc(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::itrunc<%1%>(%1%)", 0, v, 0, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline int itrunc(const number& v) Chris@16: { Chris@16: return itrunc(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline long ltrunc(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: number_type r = trunc(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, number_type(v), 0L, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long ltrunc(const detail::expression& v) Chris@16: { Chris@16: return ltrunc(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline long ltrunc(const number& v, const Policy& pol) Chris@16: { Chris@16: number r = trunc(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::ltrunc<%1%>(%1%)", 0, v, 0L, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long ltrunc(const number& v) Chris@16: { Chris@16: return ltrunc(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: #ifndef BOOST_NO_LONG_LONG Chris@16: template Chris@16: inline long long lltrunc(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: number_type r = trunc(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, number_type(v), 0LL, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long long lltrunc(const detail::expression& v) Chris@16: { Chris@16: return lltrunc(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline long long lltrunc(const number& v, const Policy& pol) Chris@16: { Chris@16: number r = trunc(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::lltrunc<%1%>(%1%)", 0, v, 0LL, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long long lltrunc(const number& v) Chris@16: { Chris@16: return lltrunc(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: #endif Chris@16: template Chris@16: inline typename detail::expression::result_type round(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: return BOOST_MP_MOVE(round(static_cast(v), pol)); Chris@16: } Chris@16: template Chris@16: inline number round(const number& v, const Policy&) Chris@16: { Chris@16: using default_ops::eval_round; Chris@16: number result; Chris@16: eval_round(result.backend(), v.backend()); Chris@16: return BOOST_MP_MOVE(result); Chris@16: } Chris@16: Chris@16: template Chris@16: inline int iround(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: number_type r = round(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline int iround(const detail::expression& v) Chris@16: { Chris@16: return iround(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline int iround(const number& v, const Policy& pol) Chris@16: { Chris@16: number r = round(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline int iround(const number& v) Chris@16: { Chris@16: return iround(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline long lround(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: number_type r = round(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, number_type(v), 0L, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long lround(const detail::expression& v) Chris@16: { Chris@16: return lround(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline long lround(const number& v, const Policy& pol) Chris@16: { Chris@16: number r = round(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::lround<%1%>(%1%)", 0, v, 0L, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long lround(const number& v) Chris@16: { Chris@16: return lround(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: #ifndef BOOST_NO_LONG_LONG Chris@16: template Chris@16: inline long long llround(const detail::expression& v, const Policy& pol) Chris@16: { Chris@16: typedef typename detail::expression::result_type number_type; Chris@16: number_type r = round(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, number_type(v), 0LL, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long long llround(const detail::expression& v) Chris@16: { Chris@16: return llround(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: template Chris@16: inline long long llround(const number& v, const Policy& pol) Chris@16: { Chris@16: number r = round(v, pol); Chris@16: if((r > (std::numeric_limits::max)()) || r < (std::numeric_limits::min)() || !(boost::math::isfinite)(v)) Chris@16: return boost::math::policies::raise_rounding_error("boost::multiprecision::iround<%1%>(%1%)", 0, v, 0LL, pol); Chris@16: return r.template convert_to(); Chris@16: } Chris@16: template Chris@16: inline long long llround(const number& v) Chris@16: { Chris@16: return llround(v, boost::math::policies::policy<>()); Chris@16: } Chris@16: #endif Chris@101: // Chris@101: // frexp does not return an expression template since we require the Chris@101: // integer argument to be evaluated even if the returned value is Chris@101: // not assigned to anything... Chris@101: // Chris@101: template Chris@101: inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, short* pint) Chris@101: { Chris@101: using default_ops::eval_frexp; Chris@101: number result; Chris@101: eval_frexp(result.backend(), v.backend(), pint); Chris@101: return BOOST_MP_MOVE(result); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type Chris@101: frexp(const detail::expression& v, short* pint) Chris@101: { Chris@101: typedef typename detail::expression::result_type number_type; Chris@101: return BOOST_MP_MOVE(frexp(static_cast(v), pint)); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, int* pint) Chris@101: { Chris@101: using default_ops::eval_frexp; Chris@101: number result; Chris@101: eval_frexp(result.backend(), v.backend(), pint); Chris@101: return BOOST_MP_MOVE(result); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type Chris@101: frexp(const detail::expression& v, int* pint) Chris@101: { Chris@101: typedef typename detail::expression::result_type number_type; Chris@101: return BOOST_MP_MOVE(frexp(static_cast(v), pint)); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, long* pint) Chris@101: { Chris@101: using default_ops::eval_frexp; Chris@101: number result; Chris@101: eval_frexp(result.backend(), v.backend(), pint); Chris@101: return BOOST_MP_MOVE(result); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type Chris@101: frexp(const detail::expression& v, long* pint) Chris@101: { Chris@101: typedef typename detail::expression::result_type number_type; Chris@101: return BOOST_MP_MOVE(frexp(static_cast(v), pint)); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::value == number_kind_floating_point, number >::type frexp(const number& v, long long* pint) Chris@101: { Chris@101: using default_ops::eval_frexp; Chris@101: number result; Chris@101: eval_frexp(result.backend(), v.backend(), pint); Chris@101: return BOOST_MP_MOVE(result); Chris@101: } Chris@101: template Chris@101: inline typename enable_if_c::result_type>::value == number_kind_floating_point, typename detail::expression::result_type>::type Chris@101: frexp(const detail::expression& v, long long* pint) Chris@101: { Chris@101: typedef typename detail::expression::result_type number_type; Chris@101: return BOOST_MP_MOVE(frexp(static_cast(v), pint)); Chris@101: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value == number_kind_integer, number >::type Chris@16: sqrt(const number& x) Chris@16: { Chris@16: using default_ops::eval_integer_sqrt; Chris@16: number s, r; Chris@16: eval_integer_sqrt(s.backend(), r.backend(), x.backend()); Chris@16: return s; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value == number_kind_integer, number >::type Chris@16: sqrt(const number& x, number& r) Chris@16: { Chris@16: using default_ops::eval_integer_sqrt; Chris@16: number s; Chris@16: eval_integer_sqrt(s.backend(), r.backend(), x.backend()); Chris@16: return s; Chris@16: } Chris@16: Chris@16: #define UNARY_OP_FUNCTOR(func, category)\ Chris@16: namespace detail{\ Chris@16: template \ Chris@16: struct BOOST_JOIN(func, _funct)\ Chris@16: {\ Chris@16: void operator()(Backend& result, const Backend& arg)const\ Chris@16: {\ Chris@16: using default_ops::BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result, arg);\ Chris@16: }\ Chris@16: };\ Chris@16: \ Chris@16: }\ Chris@16: \ Chris@16: template \ Chris@16: inline typename enable_if_c >::value == category,\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression > \ Chris@16: >::type \ Chris@16: func(const detail::expression& arg)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: > (\ Chris@16: detail::BOOST_JOIN(func, _funct) >::type>() \ Chris@16: , arg \ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c::value == category,\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number > \ Chris@16: >::type \ Chris@16: func(const number& arg)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg \ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename boost::enable_if_c<\ Chris@16: boost::multiprecision::number_category::value == category,\ Chris@16: number >::type \ Chris@16: func(const number& arg)\ Chris@16: {\ Chris@16: number result;\ Chris@16: using default_ops::BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result.backend(), arg.backend());\ Chris@16: return BOOST_MP_MOVE(result);\ Chris@16: } Chris@16: Chris@16: #define BINARY_OP_FUNCTOR(func, category)\ Chris@16: namespace detail{\ Chris@16: template \ Chris@16: struct BOOST_JOIN(func, _funct)\ Chris@16: {\ Chris@16: void operator()(Backend& result, const Backend& arg, const Backend& a)const\ Chris@16: {\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result, arg, a);\ Chris@16: }\ Chris@16: template \ Chris@16: void operator()(Backend& result, const Backend& arg, const Arithmetic& a)const\ Chris@16: {\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result, arg, a);\ Chris@16: }\ Chris@16: template \ Chris@16: void operator()(Backend& result, const Arithmetic& arg, const Backend& a)const\ Chris@16: {\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result, arg, a);\ Chris@16: }\ Chris@16: };\ Chris@16: \ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c::value == category,\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , number > \ Chris@16: >::type \ Chris@16: func(const number& arg, const number& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , number \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: (number_category::value == category) && (number_category >::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , detail::expression > \ Chris@16: >::type \ Chris@16: func(const number& arg, const detail::expression& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , detail::expression \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: (number_category::value == category) && (number_category >::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , detail::expression \ Chris@16: , number > \ Chris@16: >::type \ Chris@16: func(const detail::expression& arg, const number& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , detail::expression \ Chris@16: , number \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: (number_category >::value == category) && (number_category >::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: , detail::expression > \ Chris@16: >::type \ Chris@16: func(const detail::expression& arg, const detail::expression& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: , detail::expression \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct) >::type>() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: is_arithmetic::value && (number_category::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , Arithmetic\ Chris@16: > \ Chris@16: >::type \ Chris@16: func(const number& arg, const Arithmetic& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , Arithmetic\ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: is_arithmetic::value && (number_category >::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: , Arithmetic\ Chris@16: > \ Chris@16: >::type \ Chris@16: func(const detail::expression& arg, const Arithmetic& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: , Arithmetic\ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct) >::type>() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: is_arithmetic::value && (number_category::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , Arithmetic \ Chris@16: , number \ Chris@16: > \ Chris@16: >::type \ Chris@16: func(const Arithmetic& arg, const number& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , Arithmetic \ Chris@16: , number \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: is_arithmetic::value && (number_category >::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , Arithmetic \ Chris@16: , detail::expression \ Chris@16: > \ Chris@16: >::type \ Chris@16: func(const Arithmetic& arg, const detail::expression& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , Arithmetic \ Chris@16: , detail::expression \ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct) >::type>() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<(number_category::value == category),\ Chris@16: number >::type \ Chris@16: func(const number& arg, const number& a)\ Chris@16: {\ Chris@16: number result;\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a.backend());\ Chris@16: return BOOST_MP_MOVE(result);\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: is_arithmetic::value && (number_category::value == category),\ Chris@16: number \ Chris@16: >::type \ Chris@16: func(const number& arg, const Arithmetic& a)\ Chris@16: {\ Chris@16: typedef typename detail::canonical::type canonical_type;\ Chris@16: number result;\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), static_cast(a));\ Chris@16: return BOOST_MP_MOVE(result);\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: is_arithmetic::value && (number_category::value == category),\ Chris@16: number \ Chris@16: >::type \ Chris@16: func(const Arithmetic& a, const number& arg)\ Chris@16: {\ Chris@16: typedef typename detail::canonical::type canonical_type;\ Chris@16: number result;\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result.backend(), static_cast(a), arg.backend());\ Chris@16: return BOOST_MP_MOVE(result);\ Chris@16: }\ Chris@16: Chris@16: Chris@16: #define HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category)\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: (number_category >::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: , Arg2> \ Chris@16: >::type \ Chris@16: func(const detail::expression& arg, Arg2 const& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) >::type> \ Chris@16: , detail::expression \ Chris@16: , Arg2\ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct) >::type>() \ Chris@16: , arg, a \ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: (number_category::value == category),\ Chris@16: detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , Arg2> \ Chris@16: >::type \ Chris@16: func(const number& arg, Arg2 const& a)\ Chris@16: {\ Chris@16: return detail::expression<\ Chris@16: detail::function\ Chris@16: , detail::BOOST_JOIN(func, _funct) \ Chris@16: , number \ Chris@16: , Arg2\ Chris@16: >(\ Chris@16: detail::BOOST_JOIN(func, _funct)() \ Chris@16: , arg,\ Chris@16: a\ Chris@16: );\ Chris@16: }\ Chris@16: template \ Chris@16: inline typename enable_if_c<\ Chris@16: (number_category::value == category),\ Chris@16: number >::type \ Chris@16: func(const number& arg, Arg2 const& a)\ Chris@16: {\ Chris@16: number result;\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result.backend(), arg.backend(), a);\ Chris@16: return BOOST_MP_MOVE(result);\ Chris@16: }\ Chris@16: Chris@16: #define HETERO_BINARY_OP_FUNCTOR(func, Arg2, category)\ Chris@16: namespace detail{\ Chris@16: template \ Chris@16: struct BOOST_JOIN(func, _funct)\ Chris@16: {\ Chris@16: template \ Chris@16: void operator()(Backend& result, Backend const& arg, Arg a)const\ Chris@16: {\ Chris@16: using default_ops:: BOOST_JOIN(eval_,func);\ Chris@16: BOOST_JOIN(eval_,func)(result, arg, a);\ Chris@16: }\ Chris@16: };\ Chris@16: \ Chris@16: }\ Chris@16: \ Chris@16: HETERO_BINARY_OP_FUNCTOR_B(func, Arg2, category) Chris@16: Chris@16: namespace detail{ Chris@16: template Chris@16: struct abs_funct Chris@16: { Chris@16: void operator()(Backend& result, const Backend& arg)const Chris@16: { Chris@16: using default_ops::eval_abs; Chris@16: eval_abs(result, arg); Chris@16: } Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: template Chris@16: inline detail::expression< Chris@16: detail::function Chris@16: , detail::abs_funct >::type> Chris@16: , detail::expression > Chris@16: abs(const detail::expression& arg) Chris@16: { Chris@16: return detail::expression< Chris@16: detail::function Chris@16: , detail::abs_funct >::type> Chris@16: , detail::expression Chris@16: > ( Chris@16: detail::abs_funct >::type>() Chris@16: , arg Chris@16: ); Chris@16: } Chris@16: template Chris@16: inline detail::expression< Chris@16: detail::function Chris@16: , detail::abs_funct Chris@16: , number > Chris@16: abs(const number& arg) Chris@16: { Chris@16: return detail::expression< Chris@16: detail::function Chris@16: , detail::abs_funct Chris@16: , number Chris@16: >( Chris@16: detail::abs_funct() Chris@16: , arg Chris@16: ); Chris@16: } Chris@16: template Chris@16: inline number Chris@16: abs(const number& arg) Chris@16: { Chris@16: number result; Chris@16: using default_ops::eval_abs; Chris@16: eval_abs(result.backend(), arg.backend()); Chris@16: return BOOST_MP_MOVE(result); Chris@16: } Chris@16: Chris@16: UNARY_OP_FUNCTOR(fabs, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(sqrt, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(floor, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(ceil, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(trunc, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(round, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(exp, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(log, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(log10, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(cos, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(sin, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(tan, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(asin, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(acos, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(atan, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(cosh, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(sinh, number_kind_floating_point) Chris@16: UNARY_OP_FUNCTOR(tanh, number_kind_floating_point) Chris@16: Chris@101: HETERO_BINARY_OP_FUNCTOR(ldexp, short, number_kind_floating_point) Chris@101: //HETERO_BINARY_OP_FUNCTOR(frexp, short*, number_kind_floating_point) Chris@101: HETERO_BINARY_OP_FUNCTOR_B(ldexp, int, number_kind_floating_point) Chris@101: //HETERO_BINARY_OP_FUNCTOR_B(frexp, int*, number_kind_floating_point) Chris@16: HETERO_BINARY_OP_FUNCTOR_B(ldexp, long, number_kind_floating_point) Chris@101: //HETERO_BINARY_OP_FUNCTOR_B(frexp, long*, number_kind_floating_point) Chris@16: HETERO_BINARY_OP_FUNCTOR_B(ldexp, long long, number_kind_floating_point) Chris@101: //HETERO_BINARY_OP_FUNCTOR_B(frexp, long long*, number_kind_floating_point) Chris@16: BINARY_OP_FUNCTOR(pow, number_kind_floating_point) Chris@16: BINARY_OP_FUNCTOR(fmod, number_kind_floating_point) Chris@16: BINARY_OP_FUNCTOR(atan2, number_kind_floating_point) Chris@16: Chris@101: UNARY_OP_FUNCTOR(logb, number_kind_floating_point) Chris@101: HETERO_BINARY_OP_FUNCTOR(scalbn, short, number_kind_floating_point) Chris@101: HETERO_BINARY_OP_FUNCTOR_B(scalbn, int, number_kind_floating_point) Chris@101: HETERO_BINARY_OP_FUNCTOR_B(scalbn, long, number_kind_floating_point) Chris@101: HETERO_BINARY_OP_FUNCTOR_B(scalbn, long long, number_kind_floating_point) Chris@101: Chris@16: // Chris@16: // Integer functions: Chris@16: // Chris@16: BINARY_OP_FUNCTOR(gcd, number_kind_integer) Chris@16: BINARY_OP_FUNCTOR(lcm, number_kind_integer) Chris@16: HETERO_BINARY_OP_FUNCTOR_B(pow, unsigned, number_kind_integer) Chris@16: Chris@16: #undef BINARY_OP_FUNCTOR Chris@16: #undef UNARY_OP_FUNCTOR Chris@16: Chris@101: // Chris@101: // ilogb: Chris@101: // Chris@101: template Chris@101: inline typename enable_if_c::value == number_kind_floating_point, typename Backend::exponent_type>::type Chris@101: ilogb(const multiprecision::number& val) Chris@101: { Chris@101: using default_ops::eval_ilogb; Chris@101: return eval_ilogb(val.backend()); Chris@101: } Chris@101: Chris@101: template Chris@101: inline typename enable_if_c >::value == number_kind_floating_point, typename multiprecision::detail::expression::result_type::backend_type::exponent_type>::type Chris@101: ilogb(const detail::expression& val) Chris@101: { Chris@101: using default_ops::eval_ilogb; Chris@101: typename multiprecision::detail::expression::result_type arg(val); Chris@101: return eval_ilogb(arg.backend()); Chris@101: } Chris@101: Chris@16: } //namespace multiprecision Chris@16: Chris@16: namespace math{ Chris@16: // Chris@16: // Overload of Boost.Math functions that find the wrong overload when used with number: Chris@16: // Chris@16: namespace detail{ Chris@16: template T sinc_pi_imp(T); Chris@16: template T sinhc_pi_imp(T); Chris@16: } Chris@16: template Chris@16: inline multiprecision::number sinc_pi(const multiprecision::number& x) Chris@16: { Chris@16: return BOOST_MP_MOVE(detail::sinc_pi_imp(x)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline multiprecision::number sinc_pi(const multiprecision::number& x, const Policy&) Chris@16: { Chris@16: return BOOST_MP_MOVE(detail::sinc_pi_imp(x)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline multiprecision::number sinhc_pi(const multiprecision::number& x) Chris@16: { Chris@16: return BOOST_MP_MOVE(detail::sinhc_pi_imp(x)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline multiprecision::number sinhc_pi(const multiprecision::number& x, const Policy&) Chris@16: { Chris@16: return BOOST_MP_MOVE(boost::math::sinhc_pi(x)); Chris@16: } Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: } // namespace math Chris@16: } // namespace boost Chris@16: Chris@16: // Chris@16: // This has to come last of all: Chris@16: // Chris@16: #include Chris@16: #include Chris@16: Chris@16: #endif Chris@16: