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