Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/multiprecision/number.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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/multiprecision/number.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,1795 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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_EXTENDED_REAL_HPP +#define BOOST_MATH_EXTENDED_REAL_HPP + +#include <boost/cstdint.hpp> +#include <boost/mpl/max.hpp> +#include <boost/mpl/plus.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/find_if.hpp> +#include <boost/assert.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/type_traits/is_signed.hpp> +#include <boost/type_traits/is_unsigned.hpp> +#include <boost/type_traits/is_floating_point.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/make_unsigned.hpp> +#include <boost/throw_exception.hpp> +#include <boost/multiprecision/detail/generic_interconvert.hpp> +#include <boost/multiprecision/detail/number_compare.hpp> +#include <boost/multiprecision/traits/is_restricted_conversion.hpp> +#include <istream> // stream operators +#include <cstdio> // EOF + +namespace boost{ namespace multiprecision{ + +#ifdef BOOST_MSVC +// warning C4127: conditional expression is constant +// warning C4714: function marked as __forceinline not inlined +#pragma warning(push) +#pragma warning(disable:4127 4714) +#endif + +template <class Backend, expression_template_option ExpressionTemplates> +class number +{ + typedef number<Backend, ExpressionTemplates> self_type; +public: + typedef Backend backend_type; + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number() BOOST_NOEXCEPT_IF(noexcept(Backend())) {} + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const Backend&>(std::declval<Backend>())))) : m_backend(e.m_backend){} + template <class V> + BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c< + (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value) + && !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value + && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value + >::type* = 0) + { + m_backend = canonical_value(v); + } + template <class V> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c< + is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value + && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value + >::type* = 0) + : m_backend(canonical_value(v)) {} + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10) + : m_backend(e.m_backend, digits10){} + template <class V> + explicit BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c< + (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value) + && !detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value + && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value + >::type* = 0) + { + m_backend = canonical_value(v); + } + template <class V> + explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c< + detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value + && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value + || !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value) + >::type* = 0) + : m_backend(canonical_value(v)) {} + /* + // + // This conflicts with component based initialization (for rational and complex types) + // which is arguably more useful. Disabled for now. + // + template <class V> + number(V v, unsigned digits10, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, is_convertible<V, const char*> > >::type* dummy1 = 0) + { + m_backend.precision(digits10); + m_backend = canonical_value(v); + } + */ + template<expression_template_option ET> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number<Backend, ET>& val) + BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const Backend&>(std::declval<Backend>())))) : m_backend(val.backend()) {} + + template <class Other, expression_template_option ET> + BOOST_MP_FORCEINLINE number(const number<Other, ET>& val, + typename boost::enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0) + BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const Other&>(std::declval<Other>())))) + : m_backend(val.backend()) {} + + template <class Other, expression_template_option ET> + explicit number(const number<Other, ET>& val, typename boost::enable_if_c< + (!detail::is_explicitly_convertible<Other, Backend>::value) + >::type* = 0) + { + // + // Attempt a generic interconvertion: + // + detail::generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>()); + } + template <class Other, expression_template_option ET> + explicit BOOST_MP_FORCEINLINE number(const number<Other, ET>& val, typename boost::enable_if_c< + (detail::is_explicitly_convertible<Other, Backend>::value + && (detail::is_restricted_conversion<Other, Backend>::value || !boost::is_convertible<Other, Backend>::value)) + >::type* = 0) BOOST_NOEXCEPT_IF(noexcept(Backend(static_cast<const Other&>(std::declval<Other>())))) + : m_backend(val.backend()) {} + + template <class V> + BOOST_MP_FORCEINLINE number(V v1, V v2, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, is_convertible<V, const char*> > >::type* = 0) + { + using default_ops::assign_components; + assign_components(m_backend, canonical_value(v1), canonical_value(v2)); + } + template <class Other, expression_template_option ET> + BOOST_MP_FORCEINLINE number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename boost::enable_if<boost::is_convertible<Other, Backend> >::type* = 0) + { + using default_ops::assign_components; + assign_components(m_backend, v1.backend(), v2.backend()); + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + typedef typename is_same<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::type tag_type; + do_assign(e, tag_type()); + return *this; + } + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + typedef typename is_same<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::type tag_type; + do_assign(e, tag_type()); + return *this; + } + + BOOST_MP_FORCEINLINE number& operator=(const number& e) + BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = static_cast<const Backend&>(std::declval<Backend>()))) + { + m_backend = e.m_backend; + return *this; + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator=(const V& v) + BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = static_cast<typename boost::multiprecision::detail::canonical<V, Backend>::type const&>(std::declval<typename boost::multiprecision::detail::canonical<V, Backend>::type>()))) + { + m_backend = canonical_value(v); + return *this; + } + template <class V> + BOOST_MP_FORCEINLINE number<Backend, ExpressionTemplates>& assign(const V& v) + BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>() = static_cast<typename boost::multiprecision::detail::canonical<V, Backend>::type const&>(std::declval<typename boost::multiprecision::detail::canonical<V, Backend>::type>()))) + { + m_backend = canonical_value(v); + return *this; + } + template <class Other, expression_template_option ET> + typename boost::disable_if<boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>, number<Backend, ExpressionTemplates>& >::type + assign(const number<Other, ET>& v) + { + // + // Attempt a generic interconvertion: + // + detail::generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename boost::enable_if_c<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0) + { + *this = e; + } + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + explicit number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, + typename boost::enable_if_c<!is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value + && boost::multiprecision::detail::is_explicitly_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0) + { + assign(e); + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(number&& r) + BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend>()))) + : m_backend(static_cast<Backend&&>(r.m_backend)){} + BOOST_MP_FORCEINLINE number& operator=(number&& r) BOOST_NOEXCEPT + { + m_backend = static_cast<Backend&&>(r.m_backend); + return *this; + } +#endif + + number& operator+=(const self_type& val) + { + do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator+=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + // Create a copy if e contains this, but not if we're just doing a + // x += x + if(contains_self(e) && !is_self(e)) + { + self_type temp(e); + do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_add(e, tag()); + } + return *this; + } + + template <class Arg1, class Arg2, class Arg3, class Arg4> + number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e) + { + // + // Fused multiply-add: + // + using default_ops::eval_multiply_add; + eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref())); + return *this; + } + + template <class V> + typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator+=(const V& v) + { + using default_ops::eval_add; + eval_add(m_backend, canonical_value(v)); + return *this; + } + + number& operator-=(const self_type& val) + { + do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator-=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + // Create a copy if e contains this: + if(contains_self(e)) + { + self_type temp(e); + do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + + template <class V> + typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator-=(const V& v) + { + using default_ops::eval_subtract; + eval_subtract(m_backend, canonical_value(v)); + return *this; + } + + template <class Arg1, class Arg2, class Arg3, class Arg4> + number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e) + { + // + // Fused multiply-subtract: + // + using default_ops::eval_multiply_subtract; + eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref())); + return *this; + } + + + number& operator *= (const self_type& e) + { + do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator*=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + // Create a temporary if the RHS references *this, but not + // if we're just doing an x *= x; + if(contains_self(e) && !is_self(e)) + { + self_type temp(e); + do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + + template <class V> + typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator*=(const V& v) + { + using default_ops::eval_multiply; + eval_multiply(m_backend, canonical_value(v)); + return *this; + } + + number& operator%=(const self_type& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal()); + return *this; + } + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator%=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + // Create a temporary if the RHS references *this: + if(contains_self(e)) + { + self_type temp(e); + do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + template <class V> + typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator%=(const V& v) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + using default_ops::eval_modulus; + eval_modulus(m_backend, canonical_value(v)); + return *this; + } + + // + // These operators are *not* proto-ized. + // The issue is that the increment/decrement must happen + // even if the result of the operator *is never used*. + // Possibly we could modify our expression wrapper to + // execute the increment/decrement on destruction, but + // correct implementation will be tricky, so defered for now... + // + BOOST_MP_FORCEINLINE number& operator++() + { + using default_ops::eval_increment; + eval_increment(m_backend); + return *this; + } + + BOOST_MP_FORCEINLINE number& operator--() + { + using default_ops::eval_decrement; + eval_decrement(m_backend); + return *this; + } + + inline number operator++(int) + { + using default_ops::eval_increment; + self_type temp(*this); + eval_increment(m_backend); + return BOOST_MP_MOVE(temp); + } + + inline number operator--(int) + { + using default_ops::eval_decrement; + self_type temp(*this); + eval_decrement(m_backend); + return BOOST_MP_MOVE(temp); + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<is_integral<V>, number&>::type operator <<= (V val) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types"); + detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed<V>()); + eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val))); + return *this; + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<is_integral<V>, number&>::type operator >>= (V val) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types"); + detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed<V>()); + eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val))); + return *this; + } + + BOOST_MP_FORCEINLINE number& operator /= (const self_type& e) + { + do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator/=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + // Create a temporary if the RHS references *this: + if(contains_self(e)) + { + self_type temp(e); + do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator/=(const V& v) + { + using default_ops::eval_divide; + eval_divide(m_backend, canonical_value(v)); + return *this; + } + + BOOST_MP_FORCEINLINE number& operator&=(const self_type& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); + do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator&=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); + // Create a temporary if the RHS references *this, but not + // if we're just doing an x &= x; + if(contains_self(e) && !is_self(e)) + { + self_type temp(e); + do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator&=(const V& v) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); + using default_ops::eval_bitwise_and; + eval_bitwise_and(m_backend, canonical_value(v)); + return *this; + } + + BOOST_MP_FORCEINLINE number& operator|=(const self_type& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); + do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator|=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); + // Create a temporary if the RHS references *this, but not + // if we're just doing an x |= x; + if(contains_self(e) && !is_self(e)) + { + self_type temp(e); + do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator|=(const V& v) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); + using default_ops::eval_bitwise_or; + eval_bitwise_or(m_backend, canonical_value(v)); + return *this; + } + + BOOST_MP_FORCEINLINE number& operator^=(const self_type& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); + do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal()); + return *this; + } + + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + number& operator^=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); + if(contains_self(e)) + { + self_type temp(e); + do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + else + { + do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type()); + } + return *this; + } + + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type + operator^=(const V& v) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); + using default_ops::eval_bitwise_xor; + eval_bitwise_xor(m_backend, canonical_value(v)); + return *this; + } + // + // swap: + // + BOOST_MP_FORCEINLINE void swap(self_type& other) BOOST_NOEXCEPT + { + m_backend.swap(other.backend()); + } + // + // Zero and sign: + // + BOOST_MP_FORCEINLINE bool is_zero()const + { + using default_ops::eval_is_zero; + return eval_is_zero(m_backend); + } + BOOST_MP_FORCEINLINE int sign()const + { + using default_ops::eval_get_sign; + return eval_get_sign(m_backend); + } + // + // String conversion functions: + // + std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0))const + { + return m_backend.str(digits, f); + } + template<class Archive> + void serialize(Archive & ar, const unsigned int /*version*/) + { + ar & m_backend; + } +private: + template <class T> + void convert_to_imp(T* result)const + { + using default_ops::eval_convert_to; + eval_convert_to(result, m_backend); + } + template <class B2, expression_template_option ET> + void convert_to_imp(number<B2, ET>* result)const + { + result->assign(*this); + } + void convert_to_imp(std::string* result)const + { + *result = this->str(); + } +public: + template <class T> + T convert_to()const + { + T result; + convert_to_imp(&result); + return result; + } + // + // Use in boolean context, and explicit conversion operators: + // +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +# if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) + // + // Horrible workaround for gcc-4.6.x which always prefers the template + // operator bool() rather than the non-template operator when converting to + // an arithmetic type: + // + template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0> + explicit operator T ()const + { + using default_ops::eval_is_zero; + return !eval_is_zero(backend()); + } + template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value, int>::type = 0> + explicit operator T ()const + { + return this->template convert_to<T>(); + } +# else + template <class T> + explicit operator T()const + { + return this->template convert_to<T>(); + } + BOOST_MP_FORCEINLINE explicit operator bool()const + { + return !is_zero(); + } + explicit operator void()const {} +# endif +#else + typedef bool (self_type::*unmentionable_type)()const; + + BOOST_MP_FORCEINLINE operator unmentionable_type()const + { + return is_zero() ? 0 : &self_type::is_zero; + } +#endif + // + // Default precision: + // + static unsigned default_precision() BOOST_NOEXCEPT + { + return Backend::default_precision(); + } + static void default_precision(unsigned digits10) + { + Backend::default_precision(digits10); + } + unsigned precision()const BOOST_NOEXCEPT + { + return m_backend.precision(); + } + void precision(unsigned digits10) + { + m_backend.precision(digits10); + } + // + // Comparison: + // + BOOST_MP_FORCEINLINE int compare(const number<Backend, ExpressionTemplates>& o)const + BOOST_NOEXCEPT_IF(noexcept(std::declval<Backend>().compare(std::declval<Backend>()))) + { + return m_backend.compare(o.m_backend); + } + template <class V> + BOOST_MP_FORCEINLINE typename boost::enable_if<is_arithmetic<V>, int>::type compare(const V& o)const + { + using default_ops::eval_get_sign; + if(o == 0) + return eval_get_sign(m_backend); + return m_backend.compare(canonical_value(o)); + } + BOOST_MP_FORCEINLINE Backend& backend() BOOST_NOEXCEPT + { + return m_backend; + } + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& backend()const BOOST_NOEXCEPT + { + return m_backend; + } +private: + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::true_&) + { + do_assign(e, tag()); + } + template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> + void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::false_&) + { + // The result of the expression isn't the same type as this - + // create a temporary result and assign it to *this: + typedef typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type temp_type; + temp_type t(e); + this->assign(t); + } + + + template <class Exp> + void do_assign(const Exp& e, const detail::add_immediates&) + { + using default_ops::eval_add; + eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + template <class Exp> + void do_assign(const Exp& e, const detail::subtract_immediates&) + { + using default_ops::eval_subtract; + eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + template <class Exp> + void do_assign(const Exp& e, const detail::multiply_immediates&) + { + using default_ops::eval_multiply; + eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + template <class Exp> + void do_assign(const Exp& e, const detail::multiply_add&) + { + using default_ops::eval_multiply_add; + eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value())); + } + template <class Exp> + void do_assign(const Exp& e, const detail::multiply_subtract&) + { + using default_ops::eval_multiply_subtract; + eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value())); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::divide_immediates&) + { + using default_ops::eval_divide; + eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::negate&) + { + typedef typename Exp::left_type left_type; + do_assign(e.left(), typename left_type::tag_type()); + m_backend.negate(); + } + template <class Exp> + void do_assign(const Exp& e, const detail::plus&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + static int const left_depth = left_type::depth; + static int const right_depth = right_type::depth; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_add(e.right(), typename right_type::tag_type()); + } + else if(br && is_self(e.right())) + { + // Ignore the right node, it's *this, just add the left: + do_add(e.left(), typename left_type::tag_type()); + } + else if(bl && br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else if(!br && (bl || (left_depth >= right_depth))) + { // br is always false, but if bl is true we must take the this branch: + do_assign(e.left(), typename left_type::tag_type()); + do_add(e.right(), typename right_type::tag_type()); + } + else + { + do_assign(e.right(), typename right_type::tag_type()); + do_add(e.left(), typename left_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::minus&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + static int const left_depth = left_type::depth; + static int const right_depth = right_type::depth; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just subtract the right: + do_subtract(e.right(), typename right_type::tag_type()); + } + else if(br && is_self(e.right())) + { + // Ignore the right node, it's *this, just subtract the left and negate the result: + do_subtract(e.left(), typename left_type::tag_type()); + m_backend.negate(); + } + else if(bl && br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else if(!br && (bl || (left_depth >= right_depth))) + { // br is always false, but if bl is true we must take the this branch: + do_assign(e.left(), typename left_type::tag_type()); + do_subtract(e.right(), typename right_type::tag_type()); + } + else + { + do_assign(e.right(), typename right_type::tag_type()); + do_subtract(e.left(), typename left_type::tag_type()); + m_backend.negate(); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::multiplies&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + static int const left_depth = left_type::depth; + static int const right_depth = right_type::depth; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_multiplies(e.right(), typename right_type::tag_type()); + } + else if(br && is_self(e.right())) + { + // Ignore the right node, it's *this, just add the left: + do_multiplies(e.left(), typename left_type::tag_type()); + } + else if(bl && br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else if(!br && (bl || (left_depth >= right_depth))) + { // br is always false, but if bl is true we must take the this branch: + do_assign(e.left(), typename left_type::tag_type()); + do_multiplies(e.right(), typename right_type::tag_type()); + } + else + { + do_assign(e.right(), typename right_type::tag_type()); + do_multiplies(e.left(), typename left_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::divides&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_divide(e.right(), typename right_type::tag_type()); + } + else if(br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else + { + do_assign(e.left(), typename left_type::tag_type()); + do_divide(e.right(), typename right_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::modulus&) + { + // + // This operation is only valid for integer backends: + // + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_modulus(e.right(), typename right_type::tag_type()); + } + else if(br) + { + self_type temp(e); + temp.m_backend.swap(this->m_backend); + } + else + { + do_assign(e.left(), typename left_type::tag_type()); + do_modulus(e.right(), typename right_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::modulus_immediates&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + using default_ops::eval_modulus; + eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_and&) + { + // + // This operation is only valid for integer backends: + // + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types"); + + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + static int const left_depth = left_type::depth; + static int const right_depth = right_type::depth; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_bitwise_and(e.right(), typename right_type::tag_type()); + } + else if(br && is_self(e.right())) + { + do_bitwise_and(e.left(), typename left_type::tag_type()); + } + else if(!br && (bl || (left_depth >= right_depth))) + { + do_assign(e.left(), typename left_type::tag_type()); + do_bitwise_and(e.right(), typename right_type::tag_type()); + } + else + { + do_assign(e.right(), typename right_type::tag_type()); + do_bitwise_and(e.left(), typename left_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_and_immediates&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types"); + using default_ops::eval_bitwise_and; + eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_or&) + { + // + // This operation is only valid for integer backends: + // + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types"); + + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + static int const left_depth = left_type::depth; + static int const right_depth = right_type::depth; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_bitwise_or(e.right(), typename right_type::tag_type()); + } + else if(br && is_self(e.right())) + { + do_bitwise_or(e.left(), typename left_type::tag_type()); + } + else if(!br && (bl || (left_depth >= right_depth))) + { + do_assign(e.left(), typename left_type::tag_type()); + do_bitwise_or(e.right(), typename right_type::tag_type()); + } + else + { + do_assign(e.right(), typename right_type::tag_type()); + do_bitwise_or(e.left(), typename left_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_or_immediates&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types"); + using default_ops::eval_bitwise_or; + eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_xor&) + { + // + // This operation is only valid for integer backends: + // + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types"); + + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + + static int const left_depth = left_type::depth; + static int const right_depth = right_type::depth; + + bool bl = contains_self(e.left()); + bool br = contains_self(e.right()); + + if(bl && is_self(e.left())) + { + // Ignore the left node, it's *this, just add the right: + do_bitwise_xor(e.right(), typename right_type::tag_type()); + } + else if(br && is_self(e.right())) + { + do_bitwise_xor(e.left(), typename left_type::tag_type()); + } + else if(!br && (bl || (left_depth >= right_depth))) + { + do_assign(e.left(), typename left_type::tag_type()); + do_bitwise_xor(e.right(), typename right_type::tag_type()); + } + else + { + do_assign(e.right(), typename right_type::tag_type()); + do_bitwise_xor(e.left(), typename left_type::tag_type()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_xor_immediates&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types"); + using default_ops::eval_bitwise_xor; + eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); + } + template <class Exp> + void do_assign(const Exp& e, const detail::terminal&) + { + if(!is_self(e)) + { + m_backend = canonical_value(e.value()); + } + } + template <class Exp> + void do_assign(const Exp& e, const detail::function&) + { + typedef typename Exp::arity tag_type; + do_assign_function(e, tag_type()); + } + template <class Exp> + void do_assign(const Exp& e, const detail::shift_left&) + { + // We can only shift by an integer value, not an arbitrary expression: + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + typedef typename right_type::arity right_arity; + BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand."); + typedef typename right_type::result_type right_value_type; + BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand."); + typedef typename left_type::tag_type tag_type; + do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type()); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::shift_right&) + { + // We can only shift by an integer value, not an arbitrary expression: + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + typedef typename right_type::arity right_arity; + BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand."); + typedef typename right_type::result_type right_value_type; + BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand."); + typedef typename left_type::tag_type tag_type; + do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type()); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::bitwise_complement&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types"); + using default_ops::eval_complement; + self_type temp(e.left()); + eval_complement(m_backend, temp.backend()); + } + + template <class Exp> + void do_assign(const Exp& e, const detail::complement_immediates&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types"); + using default_ops::eval_complement; + eval_complement(m_backend, canonical_value(e.left().value())); + } + + template <class Exp, class Val> + void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types"); + using default_ops::eval_right_shift; + detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>()); + eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val)); + } + + template <class Exp, class Val> + void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types"); + using default_ops::eval_left_shift; + detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>()); + eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val)); + } + + template <class Exp, class Val, class Tag> + void do_assign_right_shift(const Exp& e, const Val& val, const Tag&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types"); + using default_ops::eval_right_shift; + self_type temp(e); + detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>()); + eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val)); + } + + template <class Exp, class Val, class Tag> + void do_assign_left_shift(const Exp& e, const Val& val, const Tag&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types"); + using default_ops::eval_left_shift; + self_type temp(e); + detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>()); + eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val)); + } + + template <class Exp> + void do_assign_function(const Exp& e, const mpl::int_<1>&) + { + e.left().value()(&m_backend); + } + template <class Exp> + void do_assign_function(const Exp& e, const mpl::int_<2>&) + { + typedef typename Exp::right_type right_type; + typedef typename right_type::tag_type tag_type; + do_assign_function_1(e.left().value(), e.right_ref(), tag_type()); + } + template <class F, class Exp> + void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&) + { + f(m_backend, function_arg_value(val)); + } + template <class F, class Exp, class Tag> + void do_assign_function_1(const F& f, const Exp& val, const Tag&) + { + number t(val); + f(m_backend, t.backend()); + } + template <class Exp> + void do_assign_function(const Exp& e, const mpl::int_<3>&) + { + typedef typename Exp::middle_type middle_type; + typedef typename middle_type::tag_type tag_type; + typedef typename Exp::right_type end_type; + typedef typename end_type::tag_type end_tag; + do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag()); + } + template <class F, class Exp1, class Exp2> + void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&) + { + f(m_backend, function_arg_value(val1), function_arg_value(val2)); + } + template <class F, class Exp1, class Exp2, class Tag1> + void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&) + { + self_type temp1(val1); + f(m_backend, BOOST_MP_MOVE(temp1.backend()), function_arg_value(val2)); + } + template <class F, class Exp1, class Exp2, class Tag2> + void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&) + { + self_type temp2(val2); + f(m_backend, function_arg_value(val1), BOOST_MP_MOVE(temp2.backend())); + } + template <class F, class Exp1, class Exp2, class Tag1, class Tag2> + void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&) + { + self_type temp1(val1); + self_type temp2(val2); + f(m_backend, BOOST_MP_MOVE(temp1.backend()), BOOST_MP_MOVE(temp2.backend())); + } + + template <class Exp> + void do_assign_function(const Exp& e, const mpl::int_<4>&) + { + typedef typename Exp::left_middle_type left_type; + typedef typename left_type::tag_type left_tag_type; + typedef typename Exp::right_middle_type middle_type; + typedef typename middle_type::tag_type middle_tag_type; + typedef typename Exp::right_type right_type; + typedef typename right_type::tag_type right_tag_type; + do_assign_function_3a(e.left().value(), e.left_middle_ref(), e.right_middle_ref(), e.right_ref(), left_tag_type(), middle_tag_type(), right_tag_type()); + } + template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3> + void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag2& t2, const Tag3& t3) + { + do_assign_function_3b(f, val1, val2, val3, t2, t3); + } + template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3> + void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag1&, const Tag2& t2, const Tag3& t3) + { + number t(val1); + do_assign_function_3b(f, BOOST_MP_MOVE(t), val2, val3, t2, t3); + } + template <class F, class Exp1, class Exp2, class Exp3, class Tag3> + void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag3& t3) + { + do_assign_function_3c(f, val1, val2, val3, t3); + } + template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3> + void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag2& /*t2*/, const Tag3& t3) + { + number t(val2); + do_assign_function_3c(f, val1, BOOST_MP_MOVE(t), val3, t3); + } + template <class F, class Exp1, class Exp2, class Exp3> + void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&) + { + f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3)); + } + template <class F, class Exp1, class Exp2, class Exp3, class Tag3> + void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/) + { + number t(val3); + do_assign_function_3c(f, val1, val2, BOOST_MP_MOVE(t), detail::terminal()); + } + + template <class Exp> + void do_add(const Exp& e, const detail::terminal&) + { + using default_ops::eval_add; + eval_add(m_backend, canonical_value(e.value())); + } + + template <class Exp> + void do_add(const Exp& e, const detail::negate&) + { + typedef typename Exp::left_type left_type; + do_subtract(e.left(), typename left_type::tag_type()); + } + + template <class Exp> + void do_add(const Exp& e, const detail::plus&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_add(e.left(), typename left_type::tag_type()); + do_add(e.right(), typename right_type::tag_type()); + } + + template <class Exp> + void do_add(const Exp& e, const detail::minus&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_add(e.left(), typename left_type::tag_type()); + do_subtract(e.right(), typename right_type::tag_type()); + } + + template <class Exp, class unknown> + void do_add(const Exp& e, const unknown&) + { + self_type temp(e); + do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + + template <class Exp> + void do_add(const Exp& e, const detail::add_immediates&) + { + using default_ops::eval_add; + eval_add(m_backend, canonical_value(e.left().value())); + eval_add(m_backend, canonical_value(e.right().value())); + } + template <class Exp> + void do_add(const Exp& e, const detail::subtract_immediates&) + { + using default_ops::eval_add; + using default_ops::eval_subtract; + eval_add(m_backend, canonical_value(e.left().value())); + eval_subtract(m_backend, canonical_value(e.right().value())); + } + template <class Exp> + void do_subtract(const Exp& e, const detail::terminal&) + { + using default_ops::eval_subtract; + eval_subtract(m_backend, canonical_value(e.value())); + } + + template <class Exp> + void do_subtract(const Exp& e, const detail::negate&) + { + typedef typename Exp::left_type left_type; + do_add(e.left(), typename left_type::tag_type()); + } + + template <class Exp> + void do_subtract(const Exp& e, const detail::plus&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_subtract(e.left(), typename left_type::tag_type()); + do_subtract(e.right(), typename right_type::tag_type()); + } + + template <class Exp> + void do_subtract(const Exp& e, const detail::minus&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_subtract(e.left(), typename left_type::tag_type()); + do_add(e.right(), typename right_type::tag_type()); + } + template <class Exp> + void do_subtract(const Exp& e, const detail::add_immediates&) + { + using default_ops::eval_subtract; + eval_subtract(m_backend, canonical_value(e.left().value())); + eval_subtract(m_backend, canonical_value(e.right().value())); + } + template <class Exp> + void do_subtract(const Exp& e, const detail::subtract_immediates&) + { + using default_ops::eval_add; + using default_ops::eval_subtract; + eval_subtract(m_backend, canonical_value(e.left().value())); + eval_add(m_backend, canonical_value(e.right().value())); + } + template <class Exp, class unknown> + void do_subtract(const Exp& e, const unknown&) + { + self_type temp(e); + do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal()); + } + + template <class Exp> + void do_multiplies(const Exp& e, const detail::terminal&) + { + using default_ops::eval_multiply; + eval_multiply(m_backend, canonical_value(e.value())); + } + + template <class Exp> + void do_multiplies(const Exp& e, const detail::negate&) + { + typedef typename Exp::left_type left_type; + do_multiplies(e.left(), typename left_type::tag_type()); + m_backend.negate(); + } + + template <class Exp> + void do_multiplies(const Exp& e, const detail::multiplies&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_multiplies(e.left(), typename left_type::tag_type()); + do_multiplies(e.right(), typename right_type::tag_type()); + } + + template <class Exp> + void do_multiplies(const Exp& e, const detail::divides&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_multiplies(e.left(), typename left_type::tag_type()); + do_divide(e.right(), typename right_type::tag_type()); + } + + template <class Exp> + void do_multiplies(const Exp& e, const detail::multiply_immediates&) + { + using default_ops::eval_multiply; + eval_multiply(m_backend, canonical_value(e.left().value())); + eval_multiply(m_backend, canonical_value(e.right().value())); + } + template <class Exp> + void do_multiplies(const Exp& e, const detail::divide_immediates&) + { + using default_ops::eval_multiply; + using default_ops::eval_divide; + eval_multiply(m_backend, canonical_value(e.left().value())); + eval_divide(m_backend, canonical_value(e.right().value())); + } + template <class Exp, class unknown> + void do_multiplies(const Exp& e, const unknown&) + { + using default_ops::eval_multiply; + self_type temp(e); + eval_multiply(m_backend, temp.m_backend); + } + + template <class Exp> + void do_divide(const Exp& e, const detail::terminal&) + { + using default_ops::eval_divide; + eval_divide(m_backend, canonical_value(e.value())); + } + + template <class Exp> + void do_divide(const Exp& e, const detail::negate&) + { + typedef typename Exp::left_type left_type; + do_divide(e.left(), typename left_type::tag_type()); + m_backend.negate(); + } + + template <class Exp> + void do_divide(const Exp& e, const detail::multiplies&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_divide(e.left(), typename left_type::tag_type()); + do_divide(e.right(), typename right_type::tag_type()); + } + + template <class Exp> + void do_divide(const Exp& e, const detail::divides&) + { + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_divide(e.left(), typename left_type::tag_type()); + do_multiplies(e.right(), typename right_type::tag_type()); + } + + template <class Exp> + void do_divides(const Exp& e, const detail::multiply_immediates&) + { + using default_ops::eval_divide; + eval_divide(m_backend, canonical_value(e.left().value())); + eval_divide(m_backend, canonical_value(e.right().value())); + } + template <class Exp> + void do_divides(const Exp& e, const detail::divide_immediates&) + { + using default_ops::eval_multiply; + using default_ops::eval_divide; + eval_divide(m_backend, canonical_value(e.left().value())); + mutiply(m_backend, canonical_value(e.right().value())); + } + + template <class Exp, class unknown> + void do_divide(const Exp& e, const unknown&) + { + using default_ops::eval_multiply; + self_type temp(e); + eval_divide(m_backend, temp.m_backend); + } + + template <class Exp> + void do_modulus(const Exp& e, const detail::terminal&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + using default_ops::eval_modulus; + eval_modulus(m_backend, canonical_value(e.value())); + } + + template <class Exp, class Unknown> + void do_modulus(const Exp& e, const Unknown&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types"); + using default_ops::eval_modulus; + self_type temp(e); + eval_modulus(m_backend, canonical_value(temp)); + } + + template <class Exp> + void do_bitwise_and(const Exp& e, const detail::terminal&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); + using default_ops::eval_bitwise_and; + eval_bitwise_and(m_backend, canonical_value(e.value())); + } + template <class Exp> + void do_bitwise_and(const Exp& e, const detail::bitwise_and&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_bitwise_and(e.left(), typename left_type::tag_type()); + do_bitwise_and(e.right(), typename right_type::tag_type()); + } + template <class Exp, class unknown> + void do_bitwise_and(const Exp& e, const unknown&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); + using default_ops::eval_bitwise_and; + self_type temp(e); + eval_bitwise_and(m_backend, temp.m_backend); + } + + template <class Exp> + void do_bitwise_or(const Exp& e, const detail::terminal&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); + using default_ops::eval_bitwise_or; + eval_bitwise_or(m_backend, canonical_value(e.value())); + } + template <class Exp> + void do_bitwise_or(const Exp& e, const detail::bitwise_or&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_bitwise_or(e.left(), typename left_type::tag_type()); + do_bitwise_or(e.right(), typename right_type::tag_type()); + } + template <class Exp, class unknown> + void do_bitwise_or(const Exp& e, const unknown&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); + using default_ops::eval_bitwise_or; + self_type temp(e); + eval_bitwise_or(m_backend, temp.m_backend); + } + + template <class Exp> + void do_bitwise_xor(const Exp& e, const detail::terminal&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); + using default_ops::eval_bitwise_xor; + eval_bitwise_xor(m_backend, canonical_value(e.value())); + } + template <class Exp> + void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); + typedef typename Exp::left_type left_type; + typedef typename Exp::right_type right_type; + do_bitwise_xor(e.left(), typename left_type::tag_type()); + do_bitwise_xor(e.right(), typename right_type::tag_type()); + } + template <class Exp, class unknown> + void do_bitwise_xor(const Exp& e, const unknown&) + { + BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); + using default_ops::eval_bitwise_xor; + self_type temp(e); + eval_bitwise_xor(m_backend, temp.m_backend); + } + + // Tests if the expression contains a reference to *this: + template <class Exp> + BOOST_MP_FORCEINLINE bool contains_self(const Exp& e)const BOOST_NOEXCEPT + { + return contains_self(e, typename Exp::arity()); + } + template <class Exp> + BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<0> const&)const BOOST_NOEXCEPT + { + return is_realy_self(e.value()); + } + template <class Exp> + BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<1> const&)const BOOST_NOEXCEPT + { + typedef typename Exp::left_type child_type; + return contains_self(e.left(), typename child_type::arity()); + } + template <class Exp> + BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<2> const&)const BOOST_NOEXCEPT + { + typedef typename Exp::left_type child0_type; + typedef typename Exp::right_type child1_type; + return contains_self(e.left(), typename child0_type::arity()) + || contains_self(e.right(), typename child1_type::arity()); + } + template <class Exp> + BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<3> const&)const BOOST_NOEXCEPT + { + typedef typename Exp::left_type child0_type; + typedef typename Exp::middle_type child1_type; + typedef typename Exp::right_type child2_type; + return contains_self(e.left(), typename child0_type::arity()) + || contains_self(e.middle(), typename child1_type::arity()) + || contains_self(e.right(), typename child2_type::arity()); + } + + // Test if the expression is a reference to *this: + template <class Exp> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e)const BOOST_NOEXCEPT + { + return is_self(e, typename Exp::arity()); + } + template <class Exp> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e, mpl::int_<0> const&)const BOOST_NOEXCEPT + { + return is_realy_self(e.value()); + } + template <class Exp, int v> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp&, mpl::int_<v> const&)const BOOST_NOEXCEPT + { + return false; + } + + template <class Val> + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const Val&)const BOOST_NOEXCEPT{ return false; } + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const self_type& v)const BOOST_NOEXCEPT{ return &v == this; } + + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const self_type& v) BOOST_NOEXCEPT { return v.backend(); } + template <class V> + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const V& function_arg_value(const V& v) BOOST_NOEXCEPT { return v; } + template <class A1, class A2, class A3, class A4> + static BOOST_MP_FORCEINLINE const A1& function_arg_value(const detail::expression<detail::terminal, A1, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value(); } + template <class A2, class A3, class A4> + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const detail::expression<detail::terminal, number<Backend>, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value().backend(); } + Backend m_backend; + +public: + // + // These shouldn't really need to be public, or even member functions, but it makes implementing + // the non-member operators way easier if they are: + // + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& canonical_value(const self_type& v) BOOST_NOEXCEPT { return v.m_backend; } + template <class B2, expression_template_option ET> + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const B2& canonical_value(const number<B2, ET>& v) BOOST_NOEXCEPT { return v.backend(); } + template <class V> + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::disable_if<is_same<typename detail::canonical<V, Backend>::type, V>, typename detail::canonical<V, Backend>::type>::type + canonical_value(const V& v) BOOST_NOEXCEPT { return static_cast<typename detail::canonical<V, Backend>::type>(v); } + template <class V> + static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::enable_if<is_same<typename detail::canonical<V, Backend>::type, V>, const V&>::type + canonical_value(const V& v) BOOST_NOEXCEPT { return v; } + static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) BOOST_NOEXCEPT { return v.c_str(); } + +}; + +template <class Backend, expression_template_option ExpressionTemplates> +inline std::ostream& operator << (std::ostream& os, const number<Backend, ExpressionTemplates>& r) +{ + std::streamsize d = os.precision(); + std::string s = r.str(d, os.flags()); + std::streamsize ss = os.width(); + if(ss > static_cast<std::streamsize>(s.size())) + { + char fill = os.fill(); + if((os.flags() & std::ios_base::left) == std::ios_base::left) + s.append(static_cast<std::string::size_type>(ss - s.size()), fill); + else + s.insert(0, static_cast<std::string::size_type>(ss - s.size()), fill); + } + return os << s; +} + +namespace detail{ + +template <class tag, class A1, class A2, class A3, class A4> +inline std::ostream& operator << (std::ostream& os, const expression<tag, A1, A2, A3, A4>& r) +{ + typedef typename expression<tag, A1, A2, A3, A4>::result_type value_type; + value_type temp(r); + return os << temp; +} + +} // namespace detail + +template <class Backend, expression_template_option ExpressionTemplates> +inline std::istream& operator >> (std::istream& is, number<Backend, ExpressionTemplates>& r) +{ + bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex; + bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct; + std::string s; + is >> s; + if(hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x'))) + s.insert(s.find_first_not_of("+-"), "0x"); + if(oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0')) + s.insert(s.find_first_not_of("+-"), "0"); + r.assign(s); + return is; +} + +template <class Backend, expression_template_option ExpressionTemplates> +BOOST_MP_FORCEINLINE void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b) +{ + a.swap(b); +} + +} // namespace multiprecision + +template <class T> +class rational; + +template <class Backend, multiprecision::expression_template_option ExpressionTemplates> +inline std::istream& operator >> (std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r) +{ + std::string s1; + multiprecision::number<Backend, ExpressionTemplates> v1, v2; + char c; + bool have_hex = false; + bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex; + bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct; + + while((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) + { + if(c == 'x' || c == 'X') + have_hex = true; + s1.append(1, c); + is.get(); + } + if(hex_format && ((s1[0] != '0') || (s1[1] != 'x'))) + s1.insert(0, "0x"); + if(oct_format && (s1[0] != '0')) + s1.insert(0, "0"); + v1.assign(s1); + s1.erase(); + if(c == '/') + { + is.get(); + while((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) + { + if(c == 'x' || c == 'X') + have_hex = true; + s1.append(1, c); + is.get(); + } + if(hex_format && ((s1[0] != '0') || (s1[1] != 'x'))) + s1.insert(0, "0x"); + if(oct_format && (s1[0] != '0')) + s1.insert(0, "0"); + v2.assign(s1); + } + else + v2 = 1; + r.assign(v1, v2); + return is; +} + +template <class T, multiprecision::expression_template_option ExpressionTemplates, class Arithmetic> +typename boost::enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator == (const rational<multiprecision::number<T, ExpressionTemplates> >& a, const Arithmetic& b) +{ + return a == multiprecision::number<T, ExpressionTemplates>(b); +} + +template <class T, multiprecision::expression_template_option ExpressionTemplates, class Arithmetic> +typename boost::enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator == (const Arithmetic& b, const rational<multiprecision::number<T, ExpressionTemplates> >& a) +{ + return a == multiprecision::number<T, ExpressionTemplates>(b); +} + +template <class T, multiprecision::expression_template_option ExpressionTemplates, class Arithmetic> +typename boost::enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator != (const rational<multiprecision::number<T, ExpressionTemplates> >& a, const Arithmetic& b) +{ + return a != multiprecision::number<T, ExpressionTemplates>(b); +} + +template <class T, multiprecision::expression_template_option ExpressionTemplates, class Arithmetic> +typename boost::enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator != (const Arithmetic& b, const rational<multiprecision::number<T, ExpressionTemplates> >& a) +{ + return a != multiprecision::number<T, ExpressionTemplates>(b); +} + +template <class T, multiprecision::expression_template_option ExpressionTemplates> +inline multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a) +{ + return a.numerator(); +} + +template <class T, multiprecision::expression_template_option ExpressionTemplates> +inline multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a) +{ + return a.denominator(); +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespaces + +#include <boost/multiprecision/detail/ublas_interop.hpp> + +#endif