stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
|
||||
// Copyright (c) 2011 John Maddock
|
||||
// Use, modification and distribution are subject to 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_MP_BIG_LANCZOS
|
||||
#define BOOST_MP_BIG_LANCZOS
|
||||
|
||||
#include <boost/math/bindings/detail/big_lanczos.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace lanczos{
|
||||
|
||||
template <class T, class Policy>
|
||||
struct lanczos;
|
||||
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
|
||||
struct lanczos<multiprecision::number<Backend, ExpressionTemplates>, Policy>
|
||||
{
|
||||
typedef typename boost::math::policies::precision<multiprecision::number<Backend, ExpressionTemplates>, Policy>::type precision_type;
|
||||
typedef typename mpl::if_c<
|
||||
precision_type::value && (precision_type::value <= 73),
|
||||
lanczos13UDT,
|
||||
typename mpl::if_c<
|
||||
precision_type::value&& (precision_type::value <= 122),
|
||||
lanczos22UDT,
|
||||
undefined_lanczos
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
} // namespace lanczos
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 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_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_DETAIL_BITSCAN_HPP
|
||||
#define BOOST_MP_DETAIL_BITSCAN_HPP
|
||||
|
||||
#include <boost/detail/endian.hpp>
|
||||
|
||||
#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
template <class Unsigned>
|
||||
inline unsigned find_lsb(Unsigned mask, const mpl::int_<0>&)
|
||||
{
|
||||
unsigned result = 0;
|
||||
while(!(mask & 1u))
|
||||
{
|
||||
mask >>= 1;
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Unsigned>
|
||||
inline unsigned find_msb(Unsigned mask, const mpl::int_<0>&)
|
||||
{
|
||||
unsigned index = 0;
|
||||
while(mask)
|
||||
{
|
||||
++index;
|
||||
mask >>= 1;
|
||||
}
|
||||
return --index;
|
||||
}
|
||||
|
||||
#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
|
||||
|
||||
#pragma intrinsic(_BitScanForward,_BitScanReverse)
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, const mpl::int_<1>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanForward(&result, mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, const mpl::int_<1>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanReverse(&result, mask);
|
||||
return result;
|
||||
}
|
||||
#ifdef _M_X64
|
||||
|
||||
#pragma intrinsic(_BitScanForward64,_BitScanReverse64)
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned __int64 mask, const mpl::int_<2>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanForward64(&result, mask);
|
||||
return result;
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask, const mpl::int_<2>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanReverse64(&result, mask);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<1>,
|
||||
#ifdef _M_X64
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(__int64),
|
||||
mpl::int_<2>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
#else
|
||||
mpl::int_<0>
|
||||
#endif
|
||||
>::type tag_type;
|
||||
return find_lsb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<1>,
|
||||
#ifdef _M_X64
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(__int64),
|
||||
mpl::int_<2>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
#else
|
||||
mpl::int_<0>
|
||||
#endif
|
||||
>::type tag_type;
|
||||
return find_msb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
|
||||
#elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return __builtin_ctz(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, mpl::int_<2> const&)
|
||||
{
|
||||
return __builtin_ctzl(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_lsb(boost::ulong_long_type mask, mpl::int_<3> const&)
|
||||
{
|
||||
return __builtin_ctzll(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return sizeof(unsigned) * CHAR_BIT - 1 - __builtin_clz(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, mpl::int_<2> const&)
|
||||
{
|
||||
return sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(boost::ulong_long_type mask, mpl::int_<3> const&)
|
||||
{
|
||||
return sizeof(boost::ulong_long_type) * CHAR_BIT - 1 - __builtin_clzll(mask);
|
||||
}
|
||||
#ifdef BOOST_HAS_INT128
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned __int128 mask, mpl::int_<0> const&)
|
||||
{
|
||||
union { unsigned __int128 v; boost::uint64_t sv[2]; } val;
|
||||
val.v = mask;
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
if(val.sv[1])
|
||||
return find_msb(val.sv[1], mpl::int_<3>()) + 64;
|
||||
return find_msb(val.sv[0], mpl::int_<3>());
|
||||
#else
|
||||
if(val.sv[0])
|
||||
return find_msb(val.sv[0], mpl::int_<3>()) + 64;
|
||||
return find_msb(val.sv[1], mpl::int_<3>());
|
||||
#endif
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned __int128 mask, mpl::int_<0> const&)
|
||||
{
|
||||
union { unsigned __int128 v; boost::uint64_t sv[2]; } val;
|
||||
val.v = mask;
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
if(val.sv[0] == 0)
|
||||
return find_lsb(val.sv[1], mpl::int_<3>()) + 64;
|
||||
return find_lsb(val.sv[0], mpl::int_<3>());
|
||||
#else
|
||||
if(val.sv[1] == 0)
|
||||
return find_lsb(val.sv[0], mpl::int_<3>()) + 64;
|
||||
return find_lsb(val.sv[1], mpl::int_<3>());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<2>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
|
||||
mpl::int_<3>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
return find_lsb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<2>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
|
||||
mpl::int_<3>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
return find_msb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
#elif defined(BOOST_INTEL)
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return _bit_scan_forward(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return _bit_scan_reverse(mask);
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
mpl::int_<0>
|
||||
>::type tag_type;
|
||||
return find_lsb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
mpl::int_<0>
|
||||
>::type tag_type;
|
||||
return find_msb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
#else
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
return find_lsb(mask, mpl::int_<0>());
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
return find_msb(mask, mpl::int_<0>());
|
||||
}
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 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_
|
||||
|
||||
#ifndef BOOST_MP_DIGITS_HPP
|
||||
#define BOOST_MP_DIGITS_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
inline unsigned long digits10_2_2(unsigned long d10)
|
||||
{
|
||||
return (d10 * 1000uL) / 301uL + ((d10 * 1000uL) % 301 ? 2u : 1u);
|
||||
}
|
||||
|
||||
inline unsigned long digits2_2_10(unsigned long d2)
|
||||
{
|
||||
return (d2 * 301uL) / 1000uL;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock.
|
||||
// Copyright Christopher Kormanyos 2013. 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_MP_DETAIL_DYNAMIC_ARRAY_HPP
|
||||
#define BOOST_MP_DETAIL_DYNAMIC_ARRAY_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <boost/multiprecision/detail/rebind.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace detail
|
||||
{
|
||||
template <class value_type, const boost::uint32_t elem_number, class my_allocator>
|
||||
struct dynamic_array : public std::vector<value_type, typename rebind<value_type, my_allocator>::type>
|
||||
{
|
||||
dynamic_array() :
|
||||
std::vector<value_type, typename rebind<value_type, my_allocator>::type>(static_cast<typename std::vector<value_type, typename rebind<value_type, my_allocator>::type>::size_type>(elem_number), static_cast<value_type>(0))
|
||||
{
|
||||
}
|
||||
|
||||
value_type* data() { return &(*(this->begin())); }
|
||||
const value_type* data() const { return &(*(this->begin())); }
|
||||
};
|
||||
} } } } // namespace boost::multiprecision::backends::detail
|
||||
|
||||
#endif // BOOST_MP_DETAIL_DYNAMIC_ARRAY_HPP
|
||||
@@ -0,0 +1,819 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_MP_ET_OPS_HPP
|
||||
#define BOOST_MP_ET_OPS_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
//
|
||||
// Non-member operators for number:
|
||||
//
|
||||
// Unary operators first.
|
||||
// Note that these *must* return by value, even though that's somewhat against
|
||||
// existing practice. The issue is that in C++11 land one could easily and legitimately
|
||||
// write:
|
||||
// auto x = +1234_my_user_defined_suffix;
|
||||
// which would result in a dangling-reference-to-temporary if unary + returned a reference
|
||||
// to it's argument. While return-by-value is obviously inefficient in other situations
|
||||
// the reality is that no one ever uses unary operator+ anyway...!
|
||||
//
|
||||
template <class B, expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CONSTEXPR const number<B, ExpressionTemplates> operator + (const number<B, ExpressionTemplates>& v) { return v; }
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline BOOST_CONSTEXPR const detail::expression<tag, Arg1, Arg2, Arg3, Arg4> operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& v) { return v; }
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, number<B, et_on> > operator - (const number<B, et_on>& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(is_signed_number<B>::value, "Negating an unsigned type results in ill-defined behavior.");
|
||||
return detail::expression<detail::negate, number<B, et_on> >(v);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG((is_signed_number<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value), "Negating an unsigned type results in ill-defined behavior.");
|
||||
return detail::expression<detail::negate, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(v);
|
||||
}
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::complement_immediates, number<B, et_on> > >::type
|
||||
operator ~ (const number<B, et_on>& v) { return detail::expression<detail::complement_immediates, number<B, et_on> >(v); }
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_complement, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator ~ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& v) { return detail::expression<detail::bitwise_complement, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(v); }
|
||||
//
|
||||
// Then addition:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator + (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::add_immediates, number<B, et_on>, V > >::type
|
||||
operator + (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::add_immediates, V, number<B, et_on> > >::type
|
||||
operator + (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::plus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator + (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::plus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator + (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Fused multiply add:
|
||||
//
|
||||
template <class V, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >::type
|
||||
operator + (const V& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(b.left(), b.right(), a);
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >::type
|
||||
operator + (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(a.left(), a.right(), b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >
|
||||
operator + (const number<B, ET>& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(b.left(), b.right(), a);
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >
|
||||
operator + (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(a.left(), a.right(), b);
|
||||
}
|
||||
//
|
||||
// Fused multiply subtract:
|
||||
//
|
||||
template <class V, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> > >::type
|
||||
operator - (const V& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >
|
||||
(detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(b.left(), b.right(), a));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >::type
|
||||
operator - (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(a.left(), a.right(), b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> > >
|
||||
operator - (const number<B, ET>& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> > >
|
||||
(detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(b.left(), b.right(), a));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >
|
||||
operator - (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(a.left(), a.right(), b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::minus, number<B, ET>, Arg1>
|
||||
operator + (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, number<B, ET>, Arg1>(a, b.left_ref());
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::minus, number<B, ET>, Arg1>
|
||||
operator + (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, number<B, ET>, Arg1>(b, a.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator + (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >(b, a.left_ref());
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::subtract_immediates, V, number<B, et_on> > >::type
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, V, number<B, et_on> >(b, a.left_ref());
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> > >::type
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> >(b, a.left_ref());
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> > >::type
|
||||
operator + (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >(detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(a.left_ref(), b.left_ref()));
|
||||
}
|
||||
//
|
||||
// Subtraction:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator - (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::subtract_immediates, number<B, et_on>, V > >::type
|
||||
operator - (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::subtract_immediates, V, number<B, et_on> > >::type
|
||||
operator - (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::minus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator - (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::minus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator - (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::plus, number<B, ET>, Arg1>
|
||||
operator - (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, number<B, ET>, Arg1>(a, b.left_ref());
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::plus, number<B, ET>, Arg1> >
|
||||
operator - (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::plus, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::plus, number<B, ET>, Arg1>(b, a.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator - (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator - (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(b, a.left_ref()));
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, V > > >::type
|
||||
operator - (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, V > >(detail::expression<detail::add_immediates, number<B, et_on>, V >(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator - (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B2, ET> > >(detail::expression<detail::add_immediates, number<B, et_on>, number<B2, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::add_immediates, V, number<B, et_on> > >::type
|
||||
operator - (const V& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, V, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::add_immediates, number<B2, ET>, number<B, et_on> > >::type
|
||||
operator - (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B2, ET>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
//
|
||||
// Multiplication:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator * (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::multiply_immediates, number<B, et_on>, V > >::type
|
||||
operator * (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::multiply_immediates, V, number<B, et_on> > >::type
|
||||
operator * (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::multiplies, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator * (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator * (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator * (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator * (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::multiplies, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator * (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >
|
||||
operator * (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::multiplies, number<B, ET>, Arg1> (a, b.left_ref()));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >
|
||||
operator * (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::multiplies, number<B, ET>, Arg1>(b, a.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator * (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator * (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >(b, a.left_ref()));
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > > >::type
|
||||
operator * (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > > (
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, V >(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator * (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > > (
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > > >::type
|
||||
operator * (const V& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, V >(b.left_ref(), a));
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator * (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> >(b.left_ref(), a));
|
||||
}
|
||||
//
|
||||
// Division:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator / (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::divide_immediates, number<B, et_on>, V > >::type
|
||||
operator / (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::divide_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::divide_immediates, V, number<B, et_on> > >::type
|
||||
operator / (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::divide_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::divides, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator / (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator / (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator / (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator / (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::divides, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator / (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divides, number<B, ET>, Arg1> >
|
||||
operator / (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divides, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::divides, number<B, ET>, Arg1>(a, b.left_ref()));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divides, Arg1, number<B, ET> > >
|
||||
operator / (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divides, Arg1, number<B, ET> > >(
|
||||
detail::expression<detail::divides, Arg1, number<B, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator / (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator / (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, V > > >::type
|
||||
operator / (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, V > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, V>(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator / (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B2, ET> > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, number<B2, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, V, number<B, et_on> > > >::type
|
||||
operator / (const V& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, V, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, V, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B2, ET>, number<B, et_on> > > >::type
|
||||
operator / (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B2, ET>, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, number<B2, ET>, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
//
|
||||
// Modulus:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator % (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value && (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus_immediates, number<B, et_on>, V > >::type
|
||||
operator % (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::modulus_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value && (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus_immediates, V, number<B, et_on> > >::type
|
||||
operator % (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator % (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator % (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator % (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator % (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator % (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Left shift:
|
||||
//
|
||||
template <class B, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), detail::expression<detail::shift_left, number<B, et_on>, I > >::type
|
||||
operator << (const number<B, et_on>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_left, number<B, et_on>, I>(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value && (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::shift_left, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I> >::type
|
||||
operator << (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_left, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I>(a, b);
|
||||
}
|
||||
//
|
||||
// Right shift:
|
||||
//
|
||||
template <class B, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::shift_right, number<B, et_on>, I > >::type
|
||||
operator >> (const number<B, et_on>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_right, number<B, et_on>, I>(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::shift_right, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I> >::type
|
||||
operator >> (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_right, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I>(a, b);
|
||||
}
|
||||
//
|
||||
// Bitwise AND:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator & (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and_immediates, number<B, et_on>, V > >::type
|
||||
operator & (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and_immediates, V, number<B, et_on> > >::type
|
||||
operator & (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator & (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator & (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator & (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator & (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator & (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Bitwise OR:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator| (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or_immediates, number<B, et_on>, V > >::type
|
||||
operator| (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or_immediates, V, number<B, et_on> > >::type
|
||||
operator| (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator| (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator| (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator| (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator| (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator| (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Bitwise XOR:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator^ (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, V > >::type
|
||||
operator^ (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_xor_immediates, V, number<B, et_on> > >::type
|
||||
operator^ (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator^ (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator^ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator^ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator^ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer), detail::expression<detail::bitwise_xor, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator^ (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 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_
|
||||
//
|
||||
// Generic routines for converting floating point values to and from decimal strings.
|
||||
// Note that these use "naive" algorithms which result in rounding error - so they
|
||||
// do not round trip to and from the string representation (but should only be out
|
||||
// in the last bit).
|
||||
//
|
||||
|
||||
#ifndef BOOST_MP_FLOAT_STRING_CVT_HPP
|
||||
#define BOOST_MP_FLOAT_STRING_CVT_HPP
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
template <class I>
|
||||
inline void round_string_up_at(std::string& s, int pos, I& expon)
|
||||
{
|
||||
//
|
||||
// Rounds up a string representation of a number at pos:
|
||||
//
|
||||
if(pos < 0)
|
||||
{
|
||||
s.insert(static_cast<std::string::size_type>(0), 1, '1');
|
||||
s.erase(s.size() - 1);
|
||||
++expon;
|
||||
}
|
||||
else if(s[pos] == '9')
|
||||
{
|
||||
s[pos] = '0';
|
||||
round_string_up_at(s, pos - 1, expon);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((pos == 0) && (s[pos] == '0') && (s.size() == 1))
|
||||
++expon;
|
||||
++s[pos];
|
||||
}
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
std::string convert_to_string(Backend b, std::streamsize digits, std::ios_base::fmtflags f)
|
||||
{
|
||||
using default_ops::eval_log10;
|
||||
using default_ops::eval_floor;
|
||||
using default_ops::eval_pow;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_divide;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_fpclassify;
|
||||
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
typedef typename Backend::exponent_type exponent_type;
|
||||
|
||||
std::string result;
|
||||
bool iszero = false;
|
||||
bool isneg = false;
|
||||
exponent_type expon = 0;
|
||||
std::streamsize org_digits = digits;
|
||||
BOOST_ASSERT(digits > 0);
|
||||
|
||||
int fpt = eval_fpclassify(b);
|
||||
|
||||
if(fpt == (int)FP_ZERO)
|
||||
{
|
||||
result = "0";
|
||||
iszero = true;
|
||||
}
|
||||
else if(fpt == (int)FP_INFINITE)
|
||||
{
|
||||
if(b.compare(ui_type(0)) < 0)
|
||||
return "-inf";
|
||||
else
|
||||
return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf";
|
||||
}
|
||||
else if(fpt == (int)FP_NAN)
|
||||
{
|
||||
return "nan";
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Start by figuring out the exponent:
|
||||
//
|
||||
isneg = b.compare(ui_type(0)) < 0;
|
||||
if(isneg)
|
||||
b.negate();
|
||||
Backend t;
|
||||
Backend ten;
|
||||
ten = ui_type(10);
|
||||
|
||||
eval_log10(t, b);
|
||||
eval_floor(t, t);
|
||||
eval_convert_to(&expon, t);
|
||||
if(-expon > std::numeric_limits<number<Backend> >::max_exponent10 - 3)
|
||||
{
|
||||
int e = -expon / 2;
|
||||
Backend t2;
|
||||
eval_pow(t2, ten, e);
|
||||
eval_multiply(t, t2, b);
|
||||
eval_multiply(t, t2);
|
||||
if(expon & 1)
|
||||
eval_multiply(t, ten);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_pow(t, ten, -expon);
|
||||
eval_multiply(t, b);
|
||||
}
|
||||
//
|
||||
// Make sure we're between [1,10) and adjust if not:
|
||||
//
|
||||
if(t.compare(ui_type(1)) < 0)
|
||||
{
|
||||
eval_multiply(t, ui_type(10));
|
||||
--expon;
|
||||
}
|
||||
else if(t.compare(ui_type(10)) >= 0)
|
||||
{
|
||||
eval_divide(t, ui_type(10));
|
||||
++expon;
|
||||
}
|
||||
Backend digit;
|
||||
ui_type cdigit;
|
||||
//
|
||||
// Adjust the number of digits required based on formatting options:
|
||||
//
|
||||
if(((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1))
|
||||
digits += expon + 1;
|
||||
if((f & std::ios_base::scientific) == std::ios_base::scientific)
|
||||
++digits;
|
||||
//
|
||||
// Extract the digits one at a time:
|
||||
//
|
||||
for(unsigned i = 0; i < digits; ++i)
|
||||
{
|
||||
eval_floor(digit, t);
|
||||
eval_convert_to(&cdigit, digit);
|
||||
result += static_cast<char>('0' + cdigit);
|
||||
eval_subtract(t, digit);
|
||||
eval_multiply(t, ten);
|
||||
}
|
||||
//
|
||||
// Possibly round result:
|
||||
//
|
||||
if(digits >= 0)
|
||||
{
|
||||
eval_floor(digit, t);
|
||||
eval_convert_to(&cdigit, digit);
|
||||
eval_subtract(t, digit);
|
||||
if((cdigit == 5) && (t.compare(ui_type(0)) == 0))
|
||||
{
|
||||
// Bankers rounding:
|
||||
if((*result.rbegin() - '0') & 1)
|
||||
{
|
||||
round_string_up_at(result, result.size() - 1, expon);
|
||||
}
|
||||
}
|
||||
else if(cdigit >= 5)
|
||||
{
|
||||
round_string_up_at(result, result.size() - 1, expon);
|
||||
}
|
||||
}
|
||||
}
|
||||
while((result.size() > digits) && result.size())
|
||||
{
|
||||
// We may get here as a result of rounding...
|
||||
if(result.size() > 1)
|
||||
result.erase(result.size() - 1);
|
||||
else
|
||||
{
|
||||
if(expon > 0)
|
||||
--expon; // so we put less padding in the result.
|
||||
else
|
||||
++expon;
|
||||
++digits;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(org_digits >= 0);
|
||||
if(isneg)
|
||||
result.insert(static_cast<std::string::size_type>(0), 1, '-');
|
||||
format_float_string(result, expon, org_digits, f, iszero);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
void convert_from_string(Backend& b, const char* p)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_pow;
|
||||
using default_ops::eval_divide;
|
||||
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
b = ui_type(0);
|
||||
if(!p || (*p == 0))
|
||||
return;
|
||||
|
||||
bool is_neg = false;
|
||||
bool is_neg_expon = false;
|
||||
static const ui_type ten = ui_type(10);
|
||||
typename Backend::exponent_type expon = 0;
|
||||
int digits_seen = 0;
|
||||
typedef std::numeric_limits<number<Backend, et_off> > limits;
|
||||
static const int max_digits = limits::is_specialized ? limits::max_digits10 + 1 : INT_MAX;
|
||||
|
||||
if(*p == '+') ++p;
|
||||
else if(*p == '-')
|
||||
{
|
||||
is_neg = true;
|
||||
++p;
|
||||
}
|
||||
if((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0))
|
||||
{
|
||||
eval_divide(b, ui_type(0));
|
||||
if(is_neg)
|
||||
b.negate();
|
||||
return;
|
||||
}
|
||||
if((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0))
|
||||
{
|
||||
b = ui_type(1);
|
||||
eval_divide(b, ui_type(0));
|
||||
if(is_neg)
|
||||
b.negate();
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Grab all the leading digits before the decimal point:
|
||||
//
|
||||
while(std::isdigit(*p))
|
||||
{
|
||||
eval_multiply(b, ten);
|
||||
eval_add(b, ui_type(*p - '0'));
|
||||
++p;
|
||||
++digits_seen;
|
||||
}
|
||||
if(*p == '.')
|
||||
{
|
||||
//
|
||||
// Grab everything after the point, stop when we've seen
|
||||
// enough digits, even if there are actually more available:
|
||||
//
|
||||
++p;
|
||||
while(std::isdigit(*p))
|
||||
{
|
||||
eval_multiply(b, ten);
|
||||
eval_add(b, ui_type(*p - '0'));
|
||||
++p;
|
||||
--expon;
|
||||
if(++digits_seen > max_digits)
|
||||
break;
|
||||
}
|
||||
while(std::isdigit(*p))
|
||||
++p;
|
||||
}
|
||||
//
|
||||
// Parse the exponent:
|
||||
//
|
||||
if((*p == 'e') || (*p == 'E'))
|
||||
{
|
||||
++p;
|
||||
if(*p == '+') ++p;
|
||||
else if(*p == '-')
|
||||
{
|
||||
is_neg_expon = true;
|
||||
++p;
|
||||
}
|
||||
typename Backend::exponent_type e2 = 0;
|
||||
while(std::isdigit(*p))
|
||||
{
|
||||
e2 *= 10;
|
||||
e2 += (*p - '0');
|
||||
++p;
|
||||
}
|
||||
if(is_neg_expon)
|
||||
e2 = -e2;
|
||||
expon += e2;
|
||||
}
|
||||
if(expon)
|
||||
{
|
||||
// Scale by 10^expon, note that 10^expon can be
|
||||
// outside the range of our number type, even though the
|
||||
// result is within range, if that looks likely, then split
|
||||
// the calculation in two:
|
||||
Backend t;
|
||||
t = ten;
|
||||
if(expon > limits::min_exponent10 + 2)
|
||||
{
|
||||
eval_pow(t, t, expon);
|
||||
eval_multiply(b, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_pow(t, t, expon + digits_seen + 1);
|
||||
eval_multiply(b, t);
|
||||
t = ten;
|
||||
eval_pow(t, t, -digits_seen - 1);
|
||||
eval_multiply(b, t);
|
||||
}
|
||||
}
|
||||
if(is_neg)
|
||||
b.negate();
|
||||
if(*p)
|
||||
{
|
||||
// Unexpected input in string:
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected characters in string being interpreted as a float128."));
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
// Copyright 2011 John Maddock. Distributed under the Boost
|
||||
// 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)
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
|
||||
template <class T>
|
||||
void calc_log2(T& num, unsigned digits)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::signed_types>::type si_type;
|
||||
|
||||
//
|
||||
// String value with 1100 digits:
|
||||
//
|
||||
static const char* string_val = "0."
|
||||
"6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875"
|
||||
"4200148102057068573368552023575813055703267075163507596193072757082837143519030703862389167347112335"
|
||||
"0115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740"
|
||||
"4303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952"
|
||||
"6066834113727387372292895649354702576265209885969320196505855476470330679365443254763274495125040606"
|
||||
"9438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608"
|
||||
"2938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866"
|
||||
"3852313818167675143866747664789088143714198549423151997354880375165861275352916610007105355824987941"
|
||||
"4729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591"
|
||||
"0708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347"
|
||||
"6481149418642386776774406069562657379600867076257199184734022651462837904883062033061144630073719489";
|
||||
//
|
||||
// Check if we can just construct from string:
|
||||
//
|
||||
if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits
|
||||
{
|
||||
num = string_val;
|
||||
return;
|
||||
}
|
||||
//
|
||||
// We calculate log2 from using the formula:
|
||||
//
|
||||
// ln(2) = 3/4 SUM[n>=0] ((-1)^n * N!^2 / (2^n(2n+1)!))
|
||||
//
|
||||
// Numerator and denominator are calculated separately and then
|
||||
// divided at the end, we also precalculate the terms up to n = 5
|
||||
// since these fit in a 32-bit integer anyway.
|
||||
//
|
||||
// See Gourdon, X., and Sebah, P. The logarithmic constant: log 2, Jan. 2004.
|
||||
// Also http://www.mpfr.org/algorithms.pdf.
|
||||
//
|
||||
num = static_cast<ui_type>(1180509120uL);
|
||||
T denom, next_term, temp;
|
||||
denom = static_cast<ui_type>(1277337600uL);
|
||||
next_term = static_cast<ui_type>(120uL);
|
||||
si_type sign = -1;
|
||||
|
||||
ui_type limit = digits / 3 + 1;
|
||||
|
||||
for(ui_type n = 6; n < limit; ++n)
|
||||
{
|
||||
temp = static_cast<ui_type>(2);
|
||||
eval_multiply(temp, ui_type(2 * n));
|
||||
eval_multiply(temp, ui_type(2 * n + 1));
|
||||
eval_multiply(num, temp);
|
||||
eval_multiply(denom, temp);
|
||||
sign = -sign;
|
||||
eval_multiply(next_term, n);
|
||||
eval_multiply(temp, next_term, next_term);
|
||||
if(sign < 0)
|
||||
temp.negate();
|
||||
eval_add(num, temp);
|
||||
}
|
||||
eval_multiply(denom, ui_type(4));
|
||||
eval_multiply(num, ui_type(3));
|
||||
INSTRUMENT_BACKEND(denom);
|
||||
INSTRUMENT_BACKEND(num);
|
||||
eval_divide(num, denom);
|
||||
INSTRUMENT_BACKEND(num);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void calc_e(T& result, unsigned digits)
|
||||
{
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
//
|
||||
// 1100 digits in string form:
|
||||
//
|
||||
const char* string_val = "2."
|
||||
"7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274"
|
||||
"2746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901"
|
||||
"1573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069"
|
||||
"5517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416"
|
||||
"9283681902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312"
|
||||
"7736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117"
|
||||
"3012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509"
|
||||
"9618188159304169035159888851934580727386673858942287922849989208680582574927961048419844436346324496"
|
||||
"8487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016"
|
||||
"7683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354"
|
||||
"0212340784981933432106817012100562788023519303322474501585390473041995777709350366041699732972508869";
|
||||
//
|
||||
// Check if we can just construct from string:
|
||||
//
|
||||
if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits
|
||||
{
|
||||
result = string_val;
|
||||
return;
|
||||
}
|
||||
|
||||
T lim;
|
||||
lim = ui_type(1);
|
||||
eval_ldexp(lim, lim, digits);
|
||||
|
||||
//
|
||||
// Standard evaluation from the definition of e: http://functions.wolfram.com/Constants/E/02/
|
||||
//
|
||||
result = ui_type(2);
|
||||
T denom;
|
||||
denom = ui_type(1);
|
||||
ui_type i = 2;
|
||||
do{
|
||||
eval_multiply(denom, i);
|
||||
eval_multiply(result, i);
|
||||
eval_add(result, ui_type(1));
|
||||
++i;
|
||||
}while(denom.compare(lim) <= 0);
|
||||
eval_divide(result, denom);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void calc_pi(T& result, unsigned digits)
|
||||
{
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type real_type;
|
||||
//
|
||||
// 1100 digits in string form:
|
||||
//
|
||||
const char* string_val = "3."
|
||||
"1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
"8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196"
|
||||
"4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273"
|
||||
"7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094"
|
||||
"3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912"
|
||||
"9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132"
|
||||
"0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235"
|
||||
"4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859"
|
||||
"5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303"
|
||||
"5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989"
|
||||
"3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913152";
|
||||
//
|
||||
// Check if we can just construct from string:
|
||||
//
|
||||
if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits
|
||||
{
|
||||
result = string_val;
|
||||
return;
|
||||
}
|
||||
|
||||
T a;
|
||||
a = ui_type(1);
|
||||
T b;
|
||||
T A(a);
|
||||
T B;
|
||||
B = real_type(0.5f);
|
||||
T D;
|
||||
D = real_type(0.25f);
|
||||
|
||||
T lim;
|
||||
lim = ui_type(1);
|
||||
eval_ldexp(lim, lim, -(int)digits);
|
||||
|
||||
//
|
||||
// This algorithm is from:
|
||||
// Schonhage, A., Grotefeld, A. F. W., and Vetter, E. Fast Algorithms: A Multitape Turing
|
||||
// Machine Implementation. BI Wissenschaftverlag, 1994.
|
||||
// Also described in MPFR's algorithm guide: http://www.mpfr.org/algorithms.pdf.
|
||||
//
|
||||
// Let:
|
||||
// a[0] = A[0] = 1
|
||||
// B[0] = 1/2
|
||||
// D[0] = 1/4
|
||||
// Then:
|
||||
// S[k+1] = (A[k]+B[k]) / 4
|
||||
// b[k] = sqrt(B[k])
|
||||
// a[k+1] = a[k]^2
|
||||
// B[k+1] = 2(A[k+1]-S[k+1])
|
||||
// D[k+1] = D[k] - 2^k(A[k+1]-B[k+1])
|
||||
// Stop when |A[k]-B[k]| <= 2^(k-p)
|
||||
// and PI = B[k]/D[k]
|
||||
|
||||
unsigned k = 1;
|
||||
|
||||
do
|
||||
{
|
||||
eval_add(result, A, B);
|
||||
eval_ldexp(result, result, -2);
|
||||
eval_sqrt(b, B);
|
||||
eval_add(a, b);
|
||||
eval_ldexp(a, a, -1);
|
||||
eval_multiply(A, a, a);
|
||||
eval_subtract(B, A, result);
|
||||
eval_ldexp(B, B, 1);
|
||||
eval_subtract(result, A, B);
|
||||
bool neg = eval_get_sign(result) < 0;
|
||||
if(neg)
|
||||
result.negate();
|
||||
if(result.compare(lim) <= 0)
|
||||
break;
|
||||
if(neg)
|
||||
result.negate();
|
||||
eval_ldexp(result, result, k - 1);
|
||||
eval_subtract(D, result);
|
||||
++k;
|
||||
eval_ldexp(lim, lim, 1);
|
||||
}
|
||||
while(true);
|
||||
|
||||
eval_divide(result, B, D);
|
||||
}
|
||||
|
||||
template <class T, const T& (*F)(void)>
|
||||
struct constant_initializer
|
||||
{
|
||||
static void do_nothing()
|
||||
{
|
||||
init.do_nothing();
|
||||
}
|
||||
private:
|
||||
struct initializer
|
||||
{
|
||||
initializer()
|
||||
{
|
||||
F();
|
||||
}
|
||||
void do_nothing()const{}
|
||||
};
|
||||
static const initializer init;
|
||||
};
|
||||
|
||||
template <class T, const T& (*F)(void)>
|
||||
typename constant_initializer<T, F>::initializer const constant_initializer<T, F>::init;
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_ln2()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
calc_log2(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_ln2<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
#ifndef BOOST_MP_THREAD_LOCAL
|
||||
#error 1
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_e()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
calc_e(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_e<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_pi()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
calc_pi(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_pi<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,884 @@
|
||||
|
||||
// Copyright Christopher Kormanyos 2002 - 2013.
|
||||
// Copyright 2011 - 2013 John Maddock. Distributed under the Boost
|
||||
// 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)
|
||||
|
||||
// This work is based on an earlier work:
|
||||
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
|
||||
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:6326) // comparison of two constants
|
||||
#endif
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T, typename U>
|
||||
inline void pow_imp(T& result, const T& t, const U& p, const mpl::false_&)
|
||||
{
|
||||
// Compute the pure power of typename T t^p.
|
||||
// Use the S-and-X binary method, as described in
|
||||
// D. E. Knuth, "The Art of Computer Programming", Vol. 2,
|
||||
// Section 4.6.3 . The resulting computational complexity
|
||||
// is order log2[abs(p)].
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<U, T>::type int_type;
|
||||
|
||||
if(&result == &t)
|
||||
{
|
||||
T temp;
|
||||
pow_imp(temp, t, p, mpl::false_());
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
|
||||
// This will store the result.
|
||||
if(U(p % U(2)) != U(0))
|
||||
{
|
||||
result = t;
|
||||
}
|
||||
else
|
||||
result = int_type(1);
|
||||
|
||||
U p2(p);
|
||||
|
||||
// The variable x stores the binary powers of t.
|
||||
T x(t);
|
||||
|
||||
while(U(p2 /= 2) != U(0))
|
||||
{
|
||||
// Square x for each binary power.
|
||||
eval_multiply(x, x);
|
||||
|
||||
const bool has_binary_power = (U(p2 % U(2)) != U(0));
|
||||
|
||||
if(has_binary_power)
|
||||
{
|
||||
// Multiply the result with each binary power contained in the exponent.
|
||||
eval_multiply(result, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline void pow_imp(T& result, const T& t, const U& p, const mpl::true_&)
|
||||
{
|
||||
// Signed integer power, just take care of the sign then call the unsigned version:
|
||||
typedef typename boost::multiprecision::detail::canonical<U, T>::type int_type;
|
||||
typedef typename make_unsigned<U>::type ui_type;
|
||||
|
||||
if(p < 0)
|
||||
{
|
||||
T temp;
|
||||
temp = static_cast<int_type>(1);
|
||||
T denom;
|
||||
pow_imp(denom, t, static_cast<ui_type>(-p), mpl::false_());
|
||||
eval_divide(result, temp, denom);
|
||||
return;
|
||||
}
|
||||
pow_imp(result, t, static_cast<ui_type>(p), mpl::false_());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename U>
|
||||
inline typename enable_if<is_integral<U> >::type eval_pow(T& result, const T& t, const U& p)
|
||||
{
|
||||
detail::pow_imp(result, t, p, boost::is_signed<U>());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hyp0F0(T& H0F0, const T& x)
|
||||
{
|
||||
// Compute the series representation of Hypergeometric0F0 taken from
|
||||
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F0/06/01/
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
|
||||
BOOST_ASSERT(&H0F0 != &x);
|
||||
long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
T t;
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
|
||||
eval_add(H0F0, x_pow_n_div_n_fact, ui_type(1));
|
||||
|
||||
T lim;
|
||||
eval_ldexp(lim, H0F0, 1 - tol);
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
|
||||
ui_type n;
|
||||
|
||||
const unsigned series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_0f0(; ; x).
|
||||
for(n = 2; n < series_limit; ++n)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
eval_add(H0F0, x_pow_n_div_n_fact);
|
||||
bool neg = eval_get_sign(x_pow_n_div_n_fact) < 0;
|
||||
if(neg)
|
||||
x_pow_n_div_n_fact.negate();
|
||||
if(lim.compare(x_pow_n_div_n_fact) > 0)
|
||||
break;
|
||||
if(neg)
|
||||
x_pow_n_div_n_fact.negate();
|
||||
}
|
||||
if(n >= series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge"));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hyp1F0(T& H1F0, const T& a, const T& x)
|
||||
{
|
||||
// Compute the series representation of Hypergeometric1F0 taken from
|
||||
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric1F0/06/01/01/
|
||||
// and also see the corresponding section for the power function (i.e. x^a).
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type;
|
||||
|
||||
BOOST_ASSERT(&H1F0 != &x);
|
||||
BOOST_ASSERT(&H1F0 != &a);
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
T pochham_a (a);
|
||||
T ap (a);
|
||||
|
||||
eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact);
|
||||
eval_add(H1F0, si_type(1));
|
||||
T lim;
|
||||
eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
|
||||
si_type n;
|
||||
T term, part;
|
||||
|
||||
const si_type series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_1f0(a; ; x).
|
||||
for(n = 2; n < series_limit; n++)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
eval_increment(ap);
|
||||
eval_multiply(pochham_a, ap);
|
||||
eval_multiply(term, pochham_a, x_pow_n_div_n_fact);
|
||||
eval_add(H1F0, term);
|
||||
if(eval_get_sign(term) < 0)
|
||||
term.negate();
|
||||
if(lim.compare(term) >= 0)
|
||||
break;
|
||||
}
|
||||
if(n >= series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge"));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_exp(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The exp function is only valid for floating point types.");
|
||||
if(&x == &result)
|
||||
{
|
||||
T temp;
|
||||
eval_exp(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type;
|
||||
typedef typename T::exponent_type exp_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type;
|
||||
|
||||
// Handle special arguments.
|
||||
int type = eval_fpclassify(x);
|
||||
bool isneg = eval_get_sign(x) < 0;
|
||||
if(type == (int)FP_NAN)
|
||||
{
|
||||
result = x;
|
||||
errno = EDOM;
|
||||
return;
|
||||
}
|
||||
else if(type == (int)FP_INFINITE)
|
||||
{
|
||||
if(isneg)
|
||||
result = ui_type(0u);
|
||||
else
|
||||
result = x;
|
||||
return;
|
||||
}
|
||||
else if(type == (int)FP_ZERO)
|
||||
{
|
||||
result = ui_type(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get local copy of argument and force it to be positive.
|
||||
T xx = x;
|
||||
T exp_series;
|
||||
if(isneg)
|
||||
xx.negate();
|
||||
|
||||
// Check the range of the argument.
|
||||
if(xx.compare(si_type(1)) <= 0)
|
||||
{
|
||||
//
|
||||
// Use series for exp(x) - 1:
|
||||
//
|
||||
T lim;
|
||||
if(std::numeric_limits<number<T, et_on> >::is_specialized)
|
||||
lim = std::numeric_limits<number<T, et_on> >::epsilon().backend();
|
||||
else
|
||||
{
|
||||
result = ui_type(1);
|
||||
eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
}
|
||||
unsigned k = 2;
|
||||
exp_series = xx;
|
||||
result = si_type(1);
|
||||
if(isneg)
|
||||
eval_subtract(result, exp_series);
|
||||
else
|
||||
eval_add(result, exp_series);
|
||||
eval_multiply(exp_series, xx);
|
||||
eval_divide(exp_series, ui_type(k));
|
||||
eval_add(result, exp_series);
|
||||
while(exp_series.compare(lim) > 0)
|
||||
{
|
||||
++k;
|
||||
eval_multiply(exp_series, xx);
|
||||
eval_divide(exp_series, ui_type(k));
|
||||
if(isneg && (k&1))
|
||||
eval_subtract(result, exp_series);
|
||||
else
|
||||
eval_add(result, exp_series);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for pure-integer arguments which can be either signed or unsigned.
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type ll;
|
||||
eval_trunc(exp_series, x);
|
||||
eval_convert_to(&ll, exp_series);
|
||||
if(x.compare(ll) == 0)
|
||||
{
|
||||
detail::pow_imp(result, get_constant_e<T>(), ll, mpl::true_());
|
||||
return;
|
||||
}
|
||||
else if(exp_series.compare(x) == 0)
|
||||
{
|
||||
// We have a value that has no fractional part, but is too large to fit
|
||||
// in a long long, in this situation the code below will fail, so
|
||||
// we're just going to assume that this will overflow:
|
||||
if(isneg)
|
||||
result = ui_type(0);
|
||||
else
|
||||
result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
|
||||
return;
|
||||
}
|
||||
|
||||
// The algorithm for exp has been taken from MPFUN.
|
||||
// exp(t) = [ (1 + r + r^2/2! + r^3/3! + r^4/4! ...)^p2 ] * 2^n
|
||||
// where p2 is a power of 2 such as 2048, r = t_prime / p2, and
|
||||
// t_prime = t - n*ln2, with n chosen to minimize the absolute
|
||||
// value of t_prime. In the resulting Taylor series, which is
|
||||
// implemented as a hypergeometric function, |r| is bounded by
|
||||
// ln2 / p2. For small arguments, no scaling is done.
|
||||
|
||||
// Compute the exponential series of the (possibly) scaled argument.
|
||||
|
||||
eval_divide(result, xx, get_constant_ln2<T>());
|
||||
exp_type n;
|
||||
eval_convert_to(&n, result);
|
||||
|
||||
// The scaling is 2^11 = 2048.
|
||||
const si_type p2 = static_cast<si_type>(si_type(1) << 11);
|
||||
|
||||
eval_multiply(exp_series, get_constant_ln2<T>(), static_cast<canonical_exp_type>(n));
|
||||
eval_subtract(exp_series, xx);
|
||||
eval_divide(exp_series, p2);
|
||||
exp_series.negate();
|
||||
hyp0F0(result, exp_series);
|
||||
|
||||
detail::pow_imp(exp_series, result, p2, mpl::true_());
|
||||
result = ui_type(1);
|
||||
eval_ldexp(result, result, n);
|
||||
eval_multiply(exp_series, result);
|
||||
|
||||
if(isneg)
|
||||
eval_divide(result, ui_type(1), exp_series);
|
||||
else
|
||||
result = exp_series;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_log(T& result, const T& arg)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
|
||||
//
|
||||
// We use a variation of http://dlmf.nist.gov/4.45#i
|
||||
// using frexp to reduce the argument to x * 2^n,
|
||||
// then let y = x - 1 and compute:
|
||||
// log(x) = log(2) * n + log1p(1 + y)
|
||||
//
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
typedef typename T::exponent_type exp_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
int s = eval_signbit(arg);
|
||||
switch(eval_fpclassify(arg))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = arg;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_INFINITE:
|
||||
if(s) break;
|
||||
result = arg;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
|
||||
result.negate();
|
||||
errno = ERANGE;
|
||||
return;
|
||||
}
|
||||
if(s)
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
return;
|
||||
}
|
||||
|
||||
exp_type e;
|
||||
T t;
|
||||
eval_frexp(t, arg, &e);
|
||||
bool alternate = false;
|
||||
|
||||
if(t.compare(fp_type(2) / fp_type(3)) <= 0)
|
||||
{
|
||||
alternate = true;
|
||||
eval_ldexp(t, t, 1);
|
||||
--e;
|
||||
}
|
||||
|
||||
eval_multiply(result, get_constant_ln2<T>(), canonical_exp_type(e));
|
||||
INSTRUMENT_BACKEND(result);
|
||||
eval_subtract(t, ui_type(1)); /* -0.3 <= t <= 0.3 */
|
||||
if(!alternate)
|
||||
t.negate(); /* 0 <= t <= 0.33333 */
|
||||
T pow = t;
|
||||
T lim;
|
||||
T t2;
|
||||
|
||||
if(alternate)
|
||||
eval_add(result, t);
|
||||
else
|
||||
eval_subtract(result, t);
|
||||
|
||||
if(std::numeric_limits<number<T, et_on> >::is_specialized)
|
||||
eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend());
|
||||
else
|
||||
eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
INSTRUMENT_BACKEND(lim);
|
||||
|
||||
ui_type k = 1;
|
||||
do
|
||||
{
|
||||
++k;
|
||||
eval_multiply(pow, t);
|
||||
eval_divide(t2, pow, k);
|
||||
INSTRUMENT_BACKEND(t2);
|
||||
if(alternate && ((k & 1) != 0))
|
||||
eval_add(result, t2);
|
||||
else
|
||||
eval_subtract(result, t2);
|
||||
INSTRUMENT_BACKEND(result);
|
||||
}while(lim.compare(t2) < 0);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_log10()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
T ten;
|
||||
ten = ui_type(10u);
|
||||
eval_log(result, ten);
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_log10<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_log10(T& result, const T& arg)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log10 function is only valid for floating point types.");
|
||||
eval_log(result, arg);
|
||||
eval_divide(result, get_constant_log10<T>());
|
||||
}
|
||||
|
||||
template <class R, class T>
|
||||
inline void eval_log2(R& result, const T& a)
|
||||
{
|
||||
eval_log(result, a);
|
||||
eval_divide(result, get_constant_ln2<R>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void eval_pow(T& result, const T& x, const T& a)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The pow function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
if((&result == &x) || (&result == &a))
|
||||
{
|
||||
T t;
|
||||
eval_pow(t, x, a);
|
||||
result = t;
|
||||
return;
|
||||
}
|
||||
|
||||
if((a.compare(si_type(1)) == 0) || (x.compare(si_type(1)) == 0))
|
||||
{
|
||||
result = x;
|
||||
return;
|
||||
}
|
||||
if(a.compare(si_type(0)) == 0)
|
||||
{
|
||||
result = si_type(1);
|
||||
return;
|
||||
}
|
||||
|
||||
int type = eval_fpclassify(x);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case FP_ZERO:
|
||||
switch(eval_fpclassify(a))
|
||||
{
|
||||
case FP_ZERO:
|
||||
result = si_type(1);
|
||||
break;
|
||||
case FP_NAN:
|
||||
result = a;
|
||||
break;
|
||||
case FP_NORMAL:
|
||||
{
|
||||
// Need to check for a an odd integer as a special case:
|
||||
try
|
||||
{
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type i;
|
||||
eval_convert_to(&i, a);
|
||||
if(a.compare(i) == 0)
|
||||
{
|
||||
if(eval_signbit(a))
|
||||
{
|
||||
if(i & 1)
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::infinity().backend();
|
||||
if(eval_signbit(x))
|
||||
result.negate();
|
||||
errno = ERANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::infinity().backend();
|
||||
errno = ERANGE;
|
||||
}
|
||||
}
|
||||
else if(i & 1)
|
||||
{
|
||||
result = x;
|
||||
}
|
||||
else
|
||||
result = si_type(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// fallthrough..
|
||||
}
|
||||
}
|
||||
default:
|
||||
if(eval_signbit(a))
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::infinity().backend();
|
||||
errno = ERANGE;
|
||||
}
|
||||
else
|
||||
result = x;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case FP_NAN:
|
||||
result = x;
|
||||
errno = ERANGE;
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
int s = eval_get_sign(a);
|
||||
if(s == 0)
|
||||
{
|
||||
result = si_type(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if(s < 0)
|
||||
{
|
||||
T t, da;
|
||||
t = a;
|
||||
t.negate();
|
||||
eval_pow(da, x, t);
|
||||
eval_divide(result, si_type(1), da);
|
||||
return;
|
||||
}
|
||||
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type an;
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type max_an =
|
||||
std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::is_specialized ?
|
||||
(std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::max)() :
|
||||
static_cast<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>(1) << (sizeof(typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type) * CHAR_BIT - 2);
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type min_an =
|
||||
std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::is_specialized ?
|
||||
(std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::min)() :
|
||||
-min_an;
|
||||
|
||||
|
||||
T fa;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
eval_convert_to(&an, a);
|
||||
if(a.compare(an) == 0)
|
||||
{
|
||||
detail::pow_imp(result, x, an, mpl::true_());
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// conversion failed, just fall through, value is not an integer.
|
||||
an = (std::numeric_limits<boost::intmax_t>::max)();
|
||||
}
|
||||
#endif
|
||||
if((eval_get_sign(x) < 0))
|
||||
{
|
||||
typename boost::multiprecision::detail::canonical<boost::uintmax_t, T>::type aun;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
eval_convert_to(&aun, a);
|
||||
if(a.compare(aun) == 0)
|
||||
{
|
||||
fa = x;
|
||||
fa.negate();
|
||||
eval_pow(result, fa, a);
|
||||
if(aun & 1u)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// conversion failed, just fall through, value is not an integer.
|
||||
}
|
||||
#endif
|
||||
eval_floor(result, a);
|
||||
// -1^INF is a special case in C99:
|
||||
if((x.compare(si_type(-1)) == 0) && (eval_fpclassify(a) == FP_INFINITE))
|
||||
{
|
||||
result = si_type(1);
|
||||
}
|
||||
else if(a.compare(result) == 0)
|
||||
{
|
||||
// exponent is so large we have no fractional part:
|
||||
if(x.compare(si_type(-1)) < 0)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::infinity().backend();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = si_type(0);
|
||||
}
|
||||
}
|
||||
else if(type == FP_INFINITE)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::infinity().backend();
|
||||
}
|
||||
else if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
T t, da;
|
||||
|
||||
eval_subtract(da, a, an);
|
||||
|
||||
if((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0) && (an < max_an) && (an > min_an))
|
||||
{
|
||||
if(a.compare(fp_type(1e-5f)) <= 0)
|
||||
{
|
||||
// Series expansion for small a.
|
||||
eval_log(t, x);
|
||||
eval_multiply(t, a);
|
||||
hyp0F0(result, t);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Series expansion for moderately sized x. Note that for large power of a,
|
||||
// the power of the integer part of a is calculated using the pown function.
|
||||
if(an)
|
||||
{
|
||||
da.negate();
|
||||
t = si_type(1);
|
||||
eval_subtract(t, x);
|
||||
hyp1F0(result, da, t);
|
||||
detail::pow_imp(t, x, an, mpl::true_());
|
||||
eval_multiply(result, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
da = a;
|
||||
da.negate();
|
||||
t = si_type(1);
|
||||
eval_subtract(t, x);
|
||||
hyp1F0(result, da, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Series expansion for pow(x, a). Note that for large power of a, the power
|
||||
// of the integer part of a is calculated using the pown function.
|
||||
if(an)
|
||||
{
|
||||
eval_log(t, x);
|
||||
eval_multiply(t, da);
|
||||
eval_exp(result, t);
|
||||
detail::pow_imp(t, x, an, mpl::true_());
|
||||
eval_multiply(result, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_log(t, x);
|
||||
eval_multiply(t, a);
|
||||
eval_exp(result, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
inline typename enable_if<is_floating_point<A>, void>::type eval_pow(T& result, const T& x, const A& a)
|
||||
{
|
||||
// Note this one is restricted to float arguments since pow.hpp already has a version for
|
||||
// integer powers....
|
||||
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_pow(result, x, c);
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
inline typename enable_if<is_arithmetic<A>, void>::type eval_pow(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_pow(result, c, a);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_exp2(T& result, const T& arg)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
|
||||
|
||||
// Check for pure-integer arguments which can be either signed or unsigned.
|
||||
typename boost::multiprecision::detail::canonical<typename T::exponent_type, T>::type i;
|
||||
T temp;
|
||||
try {
|
||||
eval_trunc(temp, arg);
|
||||
eval_convert_to(&i, temp);
|
||||
if(arg.compare(i) == 0)
|
||||
{
|
||||
temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
|
||||
eval_ldexp(result, temp, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(const boost::math::rounding_error&)
|
||||
{ /* Fallthrough */ }
|
||||
catch(const std::runtime_error&)
|
||||
{ /* Fallthrough */ }
|
||||
|
||||
temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(2u);
|
||||
eval_pow(result, temp, arg);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class T>
|
||||
void small_sinh_series(T x, T& result)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
bool neg = eval_get_sign(x) < 0;
|
||||
if(neg)
|
||||
x.negate();
|
||||
T p(x);
|
||||
T mult(x);
|
||||
eval_multiply(mult, x);
|
||||
result = x;
|
||||
ui_type k = 1;
|
||||
|
||||
T lim(x);
|
||||
eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
|
||||
do
|
||||
{
|
||||
eval_multiply(p, mult);
|
||||
eval_divide(p, ++k);
|
||||
eval_divide(p, ++k);
|
||||
eval_add(result, p);
|
||||
}while(p.compare(lim) >= 0);
|
||||
if(neg)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sinhcosh(const T& x, T* p_sinh, T* p_cosh)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
errno = EDOM;
|
||||
// fallthrough...
|
||||
case FP_INFINITE:
|
||||
if(p_sinh)
|
||||
*p_sinh = x;
|
||||
if(p_cosh)
|
||||
{
|
||||
*p_cosh = x;
|
||||
if(eval_get_sign(x) < 0)
|
||||
p_cosh->negate();
|
||||
}
|
||||
return;
|
||||
case FP_ZERO:
|
||||
if(p_sinh)
|
||||
*p_sinh = x;
|
||||
if(p_cosh)
|
||||
*p_cosh = ui_type(1);
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
bool small_sinh = eval_get_sign(x) < 0 ? x.compare(fp_type(-0.5)) > 0 : x.compare(fp_type(0.5)) < 0;
|
||||
|
||||
if(p_cosh || !small_sinh)
|
||||
{
|
||||
T e_px, e_mx;
|
||||
eval_exp(e_px, x);
|
||||
eval_divide(e_mx, ui_type(1), e_px);
|
||||
if(eval_signbit(e_mx) != eval_signbit(e_px))
|
||||
e_mx.negate(); // Handles lack of signed zero in some types
|
||||
|
||||
if(p_sinh)
|
||||
{
|
||||
if(small_sinh)
|
||||
{
|
||||
small_sinh_series(x, *p_sinh);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_subtract(*p_sinh, e_px, e_mx);
|
||||
eval_ldexp(*p_sinh, *p_sinh, -1);
|
||||
}
|
||||
}
|
||||
if(p_cosh)
|
||||
{
|
||||
eval_add(*p_cosh, e_px, e_mx);
|
||||
eval_ldexp(*p_cosh, *p_cosh, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
small_sinh_series(x, *p_sinh);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline void eval_sinh(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The sinh function is only valid for floating point types.");
|
||||
detail::sinhcosh(x, &result, static_cast<T*>(0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void eval_cosh(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The cosh function is only valid for floating point types.");
|
||||
detail::sinhcosh(x, static_cast<T*>(0), &result);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void eval_tanh(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The tanh function is only valid for floating point types.");
|
||||
T c;
|
||||
detail::sinhcosh(x, &result, &c);
|
||||
if((eval_fpclassify(result) == FP_INFINITE) && (eval_fpclassify(c) == FP_INFINITE))
|
||||
{
|
||||
bool s = eval_signbit(result) != eval_signbit(c);
|
||||
result = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
|
||||
if(s)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
eval_divide(result, c);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -0,0 +1,825 @@
|
||||
|
||||
// Copyright Christopher Kormanyos 2002 - 2011.
|
||||
// Copyright 2011 John Maddock. Distributed under the Boost
|
||||
// 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)
|
||||
|
||||
// This work is based on an earlier work:
|
||||
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
|
||||
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:6326) // comparison of two constants
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
void hyp0F1(T& result, const T& b, const T& x)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
// Compute the series representation of Hypergeometric0F1 taken from
|
||||
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F1/06/01/01/
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
T pochham_b (b);
|
||||
T bp (b);
|
||||
|
||||
eval_divide(result, x_pow_n_div_n_fact, pochham_b);
|
||||
eval_add(result, ui_type(1));
|
||||
|
||||
si_type n;
|
||||
|
||||
T tol;
|
||||
tol = ui_type(1);
|
||||
eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
eval_multiply(tol, result);
|
||||
if(eval_get_sign(tol) < 0)
|
||||
tol.negate();
|
||||
T term;
|
||||
|
||||
const int series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_0f1(; b; x).
|
||||
for(n = 2; n < series_limit; ++n)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
eval_increment(bp);
|
||||
eval_multiply(pochham_b, bp);
|
||||
|
||||
eval_divide(term, x_pow_n_div_n_fact, pochham_b);
|
||||
eval_add(result, term);
|
||||
|
||||
bool neg_term = eval_get_sign(term) < 0;
|
||||
if(neg_term)
|
||||
term.negate();
|
||||
if(term.compare(tol) <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(n >= series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H0F1 Failed to Converge"));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void eval_sin(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The sin function is only valid for floating point types.");
|
||||
if(&result == &x)
|
||||
{
|
||||
T temp;
|
||||
eval_sin(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = x;
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
// Local copy of the argument
|
||||
T xx = x;
|
||||
|
||||
// Analyze and prepare the phase of the argument.
|
||||
// Make a local, positive copy of the argument, xx.
|
||||
// The argument xx will be reduced to 0 <= xx <= pi/2.
|
||||
bool b_negate_sin = false;
|
||||
|
||||
if(eval_get_sign(x) < 0)
|
||||
{
|
||||
xx.negate();
|
||||
b_negate_sin = !b_negate_sin;
|
||||
}
|
||||
|
||||
T n_pi, t;
|
||||
// Remove even multiples of pi.
|
||||
if(xx.compare(get_constant_pi<T>()) > 0)
|
||||
{
|
||||
eval_divide(n_pi, xx, get_constant_pi<T>());
|
||||
eval_trunc(n_pi, n_pi);
|
||||
t = ui_type(2);
|
||||
eval_fmod(t, n_pi, t);
|
||||
const bool b_n_pi_is_even = eval_get_sign(t) == 0;
|
||||
eval_multiply(n_pi, get_constant_pi<T>());
|
||||
eval_subtract(xx, n_pi);
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific));
|
||||
|
||||
// Adjust signs if the multiple of pi is not even.
|
||||
if(!b_n_pi_is_even)
|
||||
{
|
||||
b_negate_sin = !b_negate_sin;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce the argument to 0 <= xx <= pi/2.
|
||||
eval_ldexp(t, get_constant_pi<T>(), -1);
|
||||
if(xx.compare(t) > 0)
|
||||
{
|
||||
eval_subtract(xx, get_constant_pi<T>(), xx);
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
}
|
||||
|
||||
eval_subtract(t, xx);
|
||||
const bool b_zero = eval_get_sign(xx) == 0;
|
||||
const bool b_pi_half = eval_get_sign(t) == 0;
|
||||
|
||||
// Check if the reduced argument is very close to 0 or pi/2.
|
||||
const bool b_near_zero = xx.compare(fp_type(1e-1)) < 0;
|
||||
const bool b_near_pi_half = t.compare(fp_type(1e-1)) < 0;;
|
||||
|
||||
if(b_zero)
|
||||
{
|
||||
result = ui_type(0);
|
||||
}
|
||||
else if(b_pi_half)
|
||||
{
|
||||
result = ui_type(1);
|
||||
}
|
||||
else if(b_near_zero)
|
||||
{
|
||||
eval_multiply(t, xx, xx);
|
||||
eval_divide(t, si_type(-4));
|
||||
T t2;
|
||||
t2 = fp_type(1.5);
|
||||
hyp0F1(result, t2, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
eval_multiply(result, xx);
|
||||
}
|
||||
else if(b_near_pi_half)
|
||||
{
|
||||
eval_multiply(t, t);
|
||||
eval_divide(t, si_type(-4));
|
||||
T t2;
|
||||
t2 = fp_type(0.5);
|
||||
hyp0F1(result, t2, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scale to a small argument for an efficient Taylor series,
|
||||
// implemented as a hypergeometric function. Use a standard
|
||||
// divide by three identity a certain number of times.
|
||||
// Here we use division by 3^9 --> (19683 = 3^9).
|
||||
|
||||
static const si_type n_scale = 9;
|
||||
static const si_type n_three_pow_scale = static_cast<si_type>(19683L);
|
||||
|
||||
eval_divide(xx, n_three_pow_scale);
|
||||
|
||||
// Now with small arguments, we are ready for a series expansion.
|
||||
eval_multiply(t, xx, xx);
|
||||
eval_divide(t, si_type(-4));
|
||||
T t2;
|
||||
t2 = fp_type(1.5);
|
||||
hyp0F1(result, t2, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
eval_multiply(result, xx);
|
||||
|
||||
// Convert back using multiple angle identity.
|
||||
for(boost::int32_t k = static_cast<boost::int32_t>(0); k < n_scale; k++)
|
||||
{
|
||||
// Rescale the cosine value using the multiple angle identity.
|
||||
eval_multiply(t2, result, ui_type(3));
|
||||
eval_multiply(t, result, result);
|
||||
eval_multiply(t, result);
|
||||
eval_multiply(t, ui_type(4));
|
||||
eval_subtract(result, t2, t);
|
||||
}
|
||||
}
|
||||
|
||||
if(b_negate_sin)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_cos(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The cos function is only valid for floating point types.");
|
||||
if(&result == &x)
|
||||
{
|
||||
T temp;
|
||||
eval_cos(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = ui_type(1);
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
// Local copy of the argument
|
||||
T xx = x;
|
||||
|
||||
// Analyze and prepare the phase of the argument.
|
||||
// Make a local, positive copy of the argument, xx.
|
||||
// The argument xx will be reduced to 0 <= xx <= pi/2.
|
||||
bool b_negate_cos = false;
|
||||
|
||||
if(eval_get_sign(x) < 0)
|
||||
{
|
||||
xx.negate();
|
||||
}
|
||||
|
||||
T n_pi, t;
|
||||
// Remove even multiples of pi.
|
||||
if(xx.compare(get_constant_pi<T>()) > 0)
|
||||
{
|
||||
eval_divide(t, xx, get_constant_pi<T>());
|
||||
eval_trunc(n_pi, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific));
|
||||
eval_multiply(t, n_pi, get_constant_pi<T>());
|
||||
BOOST_MATH_INSTRUMENT_CODE(t.str(0, std::ios_base::scientific));
|
||||
eval_subtract(xx, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
|
||||
// Adjust signs if the multiple of pi is not even.
|
||||
t = ui_type(2);
|
||||
eval_fmod(t, n_pi, t);
|
||||
const bool b_n_pi_is_even = eval_get_sign(t) == 0;
|
||||
|
||||
if(!b_n_pi_is_even)
|
||||
{
|
||||
b_negate_cos = !b_negate_cos;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce the argument to 0 <= xx <= pi/2.
|
||||
eval_ldexp(t, get_constant_pi<T>(), -1);
|
||||
int com = xx.compare(t);
|
||||
if(com > 0)
|
||||
{
|
||||
eval_subtract(xx, get_constant_pi<T>(), xx);
|
||||
b_negate_cos = !b_negate_cos;
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
}
|
||||
|
||||
const bool b_zero = eval_get_sign(xx) == 0;
|
||||
const bool b_pi_half = com == 0;
|
||||
|
||||
// Check if the reduced argument is very close to 0.
|
||||
const bool b_near_zero = xx.compare(fp_type(1e-1)) < 0;
|
||||
|
||||
if(b_zero)
|
||||
{
|
||||
result = si_type(1);
|
||||
}
|
||||
else if(b_pi_half)
|
||||
{
|
||||
result = si_type(0);
|
||||
}
|
||||
else if(b_near_zero)
|
||||
{
|
||||
eval_multiply(t, xx, xx);
|
||||
eval_divide(t, si_type(-4));
|
||||
n_pi = fp_type(0.5f);
|
||||
hyp0F1(result, n_pi, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_subtract(t, xx);
|
||||
eval_sin(result, t);
|
||||
}
|
||||
if(b_negate_cos)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_tan(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The tan function is only valid for floating point types.");
|
||||
if(&result == &x)
|
||||
{
|
||||
T temp;
|
||||
eval_tan(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
T t;
|
||||
eval_sin(result, x);
|
||||
eval_cos(t, x);
|
||||
eval_divide(result, t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hyp2F1(T& result, const T& a, const T& b, const T& c, const T& x)
|
||||
{
|
||||
// Compute the series representation of hyperg_2f1 taken from
|
||||
// Abramowitz and Stegun 15.1.1.
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
T pochham_a (a);
|
||||
T pochham_b (b);
|
||||
T pochham_c (c);
|
||||
T ap (a);
|
||||
T bp (b);
|
||||
T cp (c);
|
||||
|
||||
eval_multiply(result, pochham_a, pochham_b);
|
||||
eval_divide(result, pochham_c);
|
||||
eval_multiply(result, x_pow_n_div_n_fact);
|
||||
eval_add(result, ui_type(1));
|
||||
|
||||
T lim;
|
||||
eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
|
||||
ui_type n;
|
||||
T term;
|
||||
|
||||
const unsigned series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_2f1(a, b; c; x).
|
||||
for(n = 2; n < series_limit; ++n)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
|
||||
eval_increment(ap);
|
||||
eval_multiply(pochham_a, ap);
|
||||
eval_increment(bp);
|
||||
eval_multiply(pochham_b, bp);
|
||||
eval_increment(cp);
|
||||
eval_multiply(pochham_c, cp);
|
||||
|
||||
eval_multiply(term, pochham_a, pochham_b);
|
||||
eval_divide(term, pochham_c);
|
||||
eval_multiply(term, x_pow_n_div_n_fact);
|
||||
eval_add(result, term);
|
||||
|
||||
if(eval_get_sign(term) < 0)
|
||||
term.negate();
|
||||
if(lim.compare(term) >= 0)
|
||||
break;
|
||||
}
|
||||
if(n > series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H2F1 failed to converge."));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_asin(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
if(&result == &x)
|
||||
{
|
||||
T t(x);
|
||||
eval_asin(result, t);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
case FP_INFINITE:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = x;
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
const bool b_neg = eval_get_sign(x) < 0;
|
||||
|
||||
T xx(x);
|
||||
if(b_neg)
|
||||
xx.negate();
|
||||
|
||||
int c = xx.compare(ui_type(1));
|
||||
if(c > 0)
|
||||
{
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
}
|
||||
else if(c == 0)
|
||||
{
|
||||
result = get_constant_pi<T>();
|
||||
eval_ldexp(result, result, -1);
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
if(xx.compare(fp_type(1e-4)) < 0)
|
||||
{
|
||||
// http://functions.wolfram.com/ElementaryFunctions/ArcSin/26/01/01/
|
||||
eval_multiply(xx, xx);
|
||||
T t1, t2;
|
||||
t1 = fp_type(0.5f);
|
||||
t2 = fp_type(1.5f);
|
||||
hyp2F1(result, t1, t1, t2, xx);
|
||||
eval_multiply(result, x);
|
||||
return;
|
||||
}
|
||||
else if(xx.compare(fp_type(1 - 1e-4f)) > 0)
|
||||
{
|
||||
T dx1;
|
||||
T t1, t2;
|
||||
eval_subtract(dx1, ui_type(1), xx);
|
||||
t1 = fp_type(0.5f);
|
||||
t2 = fp_type(1.5f);
|
||||
eval_ldexp(dx1, dx1, -1);
|
||||
hyp2F1(result, t1, t1, t2, dx1);
|
||||
eval_ldexp(dx1, dx1, 2);
|
||||
eval_sqrt(t1, dx1);
|
||||
eval_multiply(result, t1);
|
||||
eval_ldexp(t1, get_constant_pi<T>(), -1);
|
||||
result.negate();
|
||||
eval_add(result, t1);
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
typedef typename boost::multiprecision::detail::canonical<long double, T>::type guess_type;
|
||||
#else
|
||||
typedef fp_type guess_type;
|
||||
#endif
|
||||
// Get initial estimate using standard math function asin.
|
||||
guess_type dd;
|
||||
eval_convert_to(&dd, xx);
|
||||
|
||||
result = (guess_type)(std::asin(dd));
|
||||
|
||||
// Newton-Raphson iteration, we should double our precision with each iteration,
|
||||
// in practice this seems to not quite work in all cases... so terminate when we
|
||||
// have at least 2/3 of the digits correct on the assumption that the correction
|
||||
// we've just added will finish the job...
|
||||
|
||||
boost::intmax_t current_precision = eval_ilogb(result);
|
||||
boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3;
|
||||
|
||||
// Newton-Raphson iteration
|
||||
while(current_precision > target_precision)
|
||||
{
|
||||
T sine, cosine;
|
||||
eval_sin(sine, result);
|
||||
eval_cos(cosine, result);
|
||||
eval_subtract(sine, xx);
|
||||
eval_divide(sine, cosine);
|
||||
eval_subtract(result, sine);
|
||||
current_precision = eval_ilogb(sine);
|
||||
if(current_precision <= (std::numeric_limits<typename T::exponent_type>::min)() + 1)
|
||||
break;
|
||||
}
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void eval_acos(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The acos function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
case FP_INFINITE:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = get_constant_pi<T>();
|
||||
eval_ldexp(result, result, -1); // divide by two.
|
||||
return;
|
||||
}
|
||||
|
||||
eval_abs(result, x);
|
||||
int c = result.compare(ui_type(1));
|
||||
|
||||
if(c > 0)
|
||||
{
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
}
|
||||
else if(c == 0)
|
||||
{
|
||||
if(eval_get_sign(x) < 0)
|
||||
result = get_constant_pi<T>();
|
||||
else
|
||||
result = ui_type(0);
|
||||
return;
|
||||
}
|
||||
|
||||
eval_asin(result, x);
|
||||
T t;
|
||||
eval_ldexp(t, get_constant_pi<T>(), -1);
|
||||
eval_subtract(result, t);
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_atan(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = x;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = x;
|
||||
return;
|
||||
case FP_INFINITE:
|
||||
if(eval_get_sign(x) < 0)
|
||||
{
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
const bool b_neg = eval_get_sign(x) < 0;
|
||||
|
||||
T xx(x);
|
||||
if(b_neg)
|
||||
xx.negate();
|
||||
|
||||
if(xx.compare(fp_type(0.1)) < 0)
|
||||
{
|
||||
T t1, t2, t3;
|
||||
t1 = ui_type(1);
|
||||
t2 = fp_type(0.5f);
|
||||
t3 = fp_type(1.5f);
|
||||
eval_multiply(xx, xx);
|
||||
xx.negate();
|
||||
hyp2F1(result, t1, t2, t3, xx);
|
||||
eval_multiply(result, x);
|
||||
return;
|
||||
}
|
||||
|
||||
if(xx.compare(fp_type(10)) > 0)
|
||||
{
|
||||
T t1, t2, t3;
|
||||
t1 = fp_type(0.5f);
|
||||
t2 = ui_type(1u);
|
||||
t3 = fp_type(1.5f);
|
||||
eval_multiply(xx, xx);
|
||||
eval_divide(xx, si_type(-1), xx);
|
||||
hyp2F1(result, t1, t2, t3, xx);
|
||||
eval_divide(result, x);
|
||||
if(!b_neg)
|
||||
result.negate();
|
||||
eval_ldexp(t1, get_constant_pi<T>(), -1);
|
||||
eval_add(result, t1);
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get initial estimate using standard math function atan.
|
||||
fp_type d;
|
||||
eval_convert_to(&d, xx);
|
||||
result = fp_type(std::atan(d));
|
||||
|
||||
// Newton-Raphson iteration, we should double our precision with each iteration,
|
||||
// in practice this seems to not quite work in all cases... so terminate when we
|
||||
// have at least 2/3 of the digits correct on the assumption that the correction
|
||||
// we've just added will finish the job...
|
||||
|
||||
boost::intmax_t current_precision = eval_ilogb(result);
|
||||
boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3;
|
||||
|
||||
T s, c, t;
|
||||
while(current_precision > target_precision)
|
||||
{
|
||||
eval_sin(s, result);
|
||||
eval_cos(c, result);
|
||||
eval_multiply(t, xx, c);
|
||||
eval_subtract(t, s);
|
||||
eval_multiply(s, t, c);
|
||||
eval_add(result, s);
|
||||
current_precision = eval_ilogb(s);
|
||||
if(current_precision <= (std::numeric_limits<typename T::exponent_type>::min)() + 1)
|
||||
break;
|
||||
}
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_atan2(T& result, const T& y, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan2 function is only valid for floating point types.");
|
||||
if(&result == &y)
|
||||
{
|
||||
T temp(y);
|
||||
eval_atan2(result, temp, x);
|
||||
return;
|
||||
}
|
||||
else if(&result == &x)
|
||||
{
|
||||
T temp(x);
|
||||
eval_atan2(result, y, temp);
|
||||
return;
|
||||
}
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
switch(eval_fpclassify(y))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = y;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
{
|
||||
if(eval_signbit(x))
|
||||
{
|
||||
result = get_constant_pi<T>();
|
||||
if(eval_signbit(y))
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = y; // Note we allow atan2(0,0) to be +-zero, even though it's mathematically undefined
|
||||
}
|
||||
return;
|
||||
}
|
||||
case FP_INFINITE:
|
||||
{
|
||||
if(eval_fpclassify(x) == FP_INFINITE)
|
||||
{
|
||||
if(eval_signbit(x))
|
||||
{
|
||||
// 3Pi/4
|
||||
eval_ldexp(result, get_constant_pi<T>(), -2);
|
||||
eval_subtract(result, get_constant_pi<T>());
|
||||
if(eval_get_sign(y) >= 0)
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pi/4
|
||||
eval_ldexp(result, get_constant_pi<T>(), -2);
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = x;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
{
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
case FP_INFINITE:
|
||||
if(eval_get_sign(x) > 0)
|
||||
result = ui_type(0);
|
||||
else
|
||||
result = get_constant_pi<T>();
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
T xx;
|
||||
eval_divide(xx, y, x);
|
||||
if(eval_get_sign(xx) < 0)
|
||||
xx.negate();
|
||||
|
||||
eval_atan(result, xx);
|
||||
|
||||
// Determine quadrant (sign) based on signs of x, y
|
||||
const bool y_neg = eval_get_sign(y) < 0;
|
||||
const bool x_neg = eval_get_sign(x) < 0;
|
||||
|
||||
if(y_neg != x_neg)
|
||||
result.negate();
|
||||
|
||||
if(x_neg)
|
||||
{
|
||||
if(y_neg)
|
||||
eval_subtract(result, get_constant_pi<T>());
|
||||
else
|
||||
eval_add(result, get_constant_pi<T>());
|
||||
}
|
||||
}
|
||||
template<class T, class A>
|
||||
inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(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_atan2(result, x, c);
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(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_atan2(result, c, a);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
+530
@@ -0,0 +1,530 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_MP_GENERIC_INTERCONVERT_HPP
|
||||
#define BOOST_MP_GENERIC_INTERCONVERT_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/default_ops.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127 6326)
|
||||
#endif
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
template <class To, class From>
|
||||
inline To do_cast(const From & from)
|
||||
{
|
||||
return static_cast<To>(from);
|
||||
}
|
||||
template <class To, class B, ::boost::multiprecision::expression_template_option et>
|
||||
inline To do_cast(const number<B, et>& from)
|
||||
{
|
||||
return from.template convert_to<To>();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_bitwise_and;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_right_shift;
|
||||
using default_ops::eval_ldexp;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_is_zero;
|
||||
// smallest unsigned type handled natively by "From" is likely to be it's limb_type:
|
||||
typedef typename canonical<unsigned char, From>::type l_limb_type;
|
||||
// get the corresponding type that we can assign to "To":
|
||||
typedef typename canonical<l_limb_type, To>::type to_type;
|
||||
From t(from);
|
||||
bool is_neg = eval_get_sign(t) < 0;
|
||||
if(is_neg)
|
||||
t.negate();
|
||||
// Pick off the first limb:
|
||||
l_limb_type limb;
|
||||
l_limb_type mask = static_cast<l_limb_type>(~static_cast<l_limb_type>(0));
|
||||
From fl;
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
to = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<l_limb_type>::digits);
|
||||
//
|
||||
// Then keep picking off more limbs until "t" is zero:
|
||||
//
|
||||
To l;
|
||||
unsigned shift = std::numeric_limits<l_limb_type>::digits;
|
||||
while(!eval_is_zero(t))
|
||||
{
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
l = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<l_limb_type>::digits);
|
||||
eval_ldexp(l, l, shift);
|
||||
eval_add(to, l);
|
||||
shift += std::numeric_limits<l_limb_type>::digits;
|
||||
}
|
||||
//
|
||||
// Finish off by setting the sign:
|
||||
//
|
||||
if(is_neg)
|
||||
to.negate();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_bitwise_and;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_right_shift;
|
||||
using default_ops::eval_left_shift;
|
||||
using default_ops::eval_bitwise_or;
|
||||
using default_ops::eval_is_zero;
|
||||
// smallest unsigned type handled natively by "From" is likely to be it's limb_type:
|
||||
typedef typename canonical<unsigned char, From>::type limb_type;
|
||||
// get the corresponding type that we can assign to "To":
|
||||
typedef typename canonical<limb_type, To>::type to_type;
|
||||
From t(from);
|
||||
bool is_neg = eval_get_sign(t) < 0;
|
||||
if(is_neg)
|
||||
t.negate();
|
||||
// Pick off the first limb:
|
||||
limb_type limb;
|
||||
limb_type mask = static_cast<limb_type>(~static_cast<limb_type>(0));
|
||||
From fl;
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
to = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
||||
//
|
||||
// Then keep picking off more limbs until "t" is zero:
|
||||
//
|
||||
To l;
|
||||
unsigned shift = std::numeric_limits<limb_type>::digits;
|
||||
while(!eval_is_zero(t))
|
||||
{
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
l = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
||||
eval_left_shift(l, shift);
|
||||
eval_bitwise_or(to, l);
|
||||
shift += std::numeric_limits<limb_type>::digits;
|
||||
}
|
||||
//
|
||||
// Finish off by setting the sign:
|
||||
//
|
||||
if(is_neg)
|
||||
to.negate();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
//
|
||||
// The code here only works when the radix of "From" is 2, we could try shifting by other
|
||||
// radixes but it would complicate things.... use a string conversion when the radix is other
|
||||
// than 2:
|
||||
//
|
||||
if(std::numeric_limits<number<From> >::radix != 2)
|
||||
{
|
||||
to = from.str(0, std::ios_base::fmtflags()).c_str();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
typedef typename canonical<unsigned char, To>::type ui_type;
|
||||
|
||||
using default_ops::eval_fpclassify;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_is_zero;
|
||||
|
||||
//
|
||||
// First classify the input, then handle the special cases:
|
||||
//
|
||||
int c = eval_fpclassify(from);
|
||||
|
||||
if(c == (int)FP_ZERO)
|
||||
{
|
||||
to = ui_type(0);
|
||||
return;
|
||||
}
|
||||
else if(c == (int)FP_NAN)
|
||||
{
|
||||
to = static_cast<const char*>("nan");
|
||||
return;
|
||||
}
|
||||
else if(c == (int)FP_INFINITE)
|
||||
{
|
||||
to = static_cast<const char*>("inf");
|
||||
if(eval_get_sign(from) < 0)
|
||||
to.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
typename From::exponent_type e;
|
||||
From f, term;
|
||||
to = ui_type(0);
|
||||
|
||||
eval_frexp(f, from, &e);
|
||||
|
||||
static const int shift = std::numeric_limits<boost::intmax_t>::digits - 1;
|
||||
|
||||
while(!eval_is_zero(f))
|
||||
{
|
||||
// extract int sized bits from f:
|
||||
eval_ldexp(f, f, shift);
|
||||
eval_floor(term, f);
|
||||
e -= shift;
|
||||
eval_ldexp(to, to, shift);
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, To>::type ll;
|
||||
eval_convert_to(&ll, term);
|
||||
eval_add(to, ll);
|
||||
eval_subtract(f, term);
|
||||
}
|
||||
typedef typename To::exponent_type to_exponent;
|
||||
if((e > (std::numeric_limits<to_exponent>::max)()) || (e < (std::numeric_limits<to_exponent>::min)()))
|
||||
{
|
||||
to = static_cast<const char*>("inf");
|
||||
if(eval_get_sign(from) < 0)
|
||||
to.negate();
|
||||
return;
|
||||
}
|
||||
eval_ldexp(to, to, static_cast<to_exponent>(e));
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
||||
{
|
||||
typedef typename component_type<number<To> >::type to_component_type;
|
||||
|
||||
number<From> t(from);
|
||||
to_component_type n(numerator(t)), d(denominator(t));
|
||||
using default_ops::assign_components;
|
||||
assign_components(to, n.backend(), d.backend());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
||||
{
|
||||
typedef typename component_type<number<To> >::type to_component_type;
|
||||
|
||||
number<From> t(from);
|
||||
to_component_type n(t), d(1);
|
||||
using default_ops::assign_components;
|
||||
assign_components(to, n.backend(), d.backend());
|
||||
}
|
||||
|
||||
template <class R, class LargeInteger>
|
||||
R safe_convert_to_float(const LargeInteger& i)
|
||||
{
|
||||
using std::ldexp;
|
||||
if(!i)
|
||||
return R(0);
|
||||
if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::max_exponent)
|
||||
{
|
||||
LargeInteger val(i);
|
||||
if(val.sign() < 0)
|
||||
val = -val;
|
||||
unsigned mb = msb(val);
|
||||
if(mb >= std::numeric_limits<R>::max_exponent)
|
||||
{
|
||||
int scale_factor = (int)mb + 1 - std::numeric_limits<R>::max_exponent;
|
||||
BOOST_ASSERT(scale_factor >= 1);
|
||||
val >>= scale_factor;
|
||||
R result = val.template convert_to<R>();
|
||||
if(std::numeric_limits<R>::digits == 0 || std::numeric_limits<R>::digits >= std::numeric_limits<R>::max_exponent)
|
||||
{
|
||||
//
|
||||
// Calculate and add on the remainder, only if there are more
|
||||
// digits in the mantissa that the size of the exponent, in
|
||||
// other words if we are dropping digits in the conversion
|
||||
// otherwise:
|
||||
//
|
||||
LargeInteger remainder(i);
|
||||
remainder &= (LargeInteger(1) << scale_factor) - 1;
|
||||
result += ldexp(safe_convert_to_float<R>(remainder), -scale_factor);
|
||||
}
|
||||
return i.sign() < 0 ? static_cast<R>(-result) : result;
|
||||
}
|
||||
}
|
||||
return i.template convert_to<R>();
|
||||
}
|
||||
|
||||
template <class To, class Integer>
|
||||
inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&)
|
||||
{
|
||||
//
|
||||
// If we get here, then there's something about one type or the other
|
||||
// that prevents an exactly rounded result from being calculated
|
||||
// (or at least it's not clear how to implement such a thing).
|
||||
//
|
||||
using default_ops::eval_divide;
|
||||
number<To> fn(safe_convert_to_float<number<To> >(n)), fd(safe_convert_to_float<number<To> >(d));
|
||||
eval_divide(result, fn.backend(), fd.backend());
|
||||
}
|
||||
template <class To, class Integer>
|
||||
inline typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&)
|
||||
{
|
||||
//
|
||||
// If we get here, then there's something about one type or the other
|
||||
// that prevents an exactly rounded result from being calculated
|
||||
// (or at least it's not clear how to implement such a thing).
|
||||
//
|
||||
To fd(safe_convert_to_float<To>(d));
|
||||
result = safe_convert_to_float<To>(n);
|
||||
result /= fd;
|
||||
}
|
||||
|
||||
template <class To, class Integer>
|
||||
typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_&)
|
||||
{
|
||||
//
|
||||
// If we get here, then the precision of type To is known, and the integer type is unbounded
|
||||
// so we can use integer division plus manipulation of the remainder to get an exactly
|
||||
// rounded result.
|
||||
//
|
||||
if(num == 0)
|
||||
{
|
||||
result = 0;
|
||||
return;
|
||||
}
|
||||
bool s = false;
|
||||
if(num < 0)
|
||||
{
|
||||
s = true;
|
||||
num = -num;
|
||||
}
|
||||
int denom_bits = msb(denom);
|
||||
int shift = std::numeric_limits<To>::digits + denom_bits - msb(num);
|
||||
if(shift > 0)
|
||||
num <<= shift;
|
||||
else if(shift < 0)
|
||||
denom <<= boost::multiprecision::detail::unsigned_abs(shift);
|
||||
Integer q, r;
|
||||
divide_qr(num, denom, q, r);
|
||||
int q_bits = msb(q);
|
||||
if(q_bits == std::numeric_limits<To>::digits - 1)
|
||||
{
|
||||
//
|
||||
// Round up if 2 * r > denom:
|
||||
//
|
||||
r <<= 1;
|
||||
int c = r.compare(denom);
|
||||
if(c > 0)
|
||||
++q;
|
||||
else if((c == 0) && (q & 1u))
|
||||
{
|
||||
++q;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(q_bits == std::numeric_limits<To>::digits);
|
||||
//
|
||||
// We basically already have the rounding info:
|
||||
//
|
||||
if(q & 1u)
|
||||
{
|
||||
if(r || (q & 2u))
|
||||
++q;
|
||||
}
|
||||
}
|
||||
using std::ldexp;
|
||||
result = do_cast<To>(q);
|
||||
result = ldexp(result, -shift);
|
||||
if(s)
|
||||
result = -result;
|
||||
}
|
||||
template <class To, class Integer>
|
||||
inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_& tag)
|
||||
{
|
||||
number<To> t;
|
||||
generic_convert_rational_to_float_imp(t, num, denom, tag);
|
||||
result = t.backend();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
inline void generic_convert_rational_to_float(To& result, const From& f)
|
||||
{
|
||||
//
|
||||
// Type From is always a Backend to number<>, or an
|
||||
// instance of number<>, but we allow
|
||||
// To to be either a Backend type, or a real number type,
|
||||
// that way we can call this from generic conversions, and
|
||||
// from specific conversions to built in types.
|
||||
//
|
||||
typedef typename mpl::if_c<is_number<From>::value, From, number<From> >::type actual_from_type;
|
||||
typedef typename mpl::if_c<is_number<To>::value || is_floating_point<To>::value, To, number<To> >::type actual_to_type;
|
||||
typedef typename component_type<actual_from_type>::type integer_type;
|
||||
typedef mpl::bool_<!std::numeric_limits<integer_type>::is_specialized
|
||||
|| std::numeric_limits<integer_type>::is_bounded
|
||||
|| !std::numeric_limits<actual_to_type>::is_specialized
|
||||
|| !std::numeric_limits<actual_to_type>::is_bounded
|
||||
|| (std::numeric_limits<actual_to_type>::radix != 2)> dispatch_tag;
|
||||
|
||||
integer_type n(numerator(static_cast<actual_from_type>(f))), d(denominator(static_cast<actual_from_type>(f)));
|
||||
generic_convert_rational_to_float_imp(result, n, d, dispatch_tag());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
inline void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
||||
{
|
||||
generic_convert_rational_to_float(to, from);
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/)
|
||||
{
|
||||
typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
|
||||
static const int shift = std::numeric_limits<boost::long_long_type>::digits;
|
||||
typename From::exponent_type e;
|
||||
typename component_type<number<To> >::type num, denom;
|
||||
number<From> val(from);
|
||||
val = frexp(val, &e);
|
||||
while(val)
|
||||
{
|
||||
val = ldexp(val, shift);
|
||||
e -= shift;
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
num <<= shift;
|
||||
num += ll;
|
||||
}
|
||||
denom = ui_type(1u);
|
||||
if(e < 0)
|
||||
denom <<= -e;
|
||||
else if(e > 0)
|
||||
num <<= e;
|
||||
assign_components(to, num.backend(), denom.backend());
|
||||
}
|
||||
|
||||
template <class To, class From, int Radix>
|
||||
void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<Radix>& /*radix*/)
|
||||
{
|
||||
//
|
||||
// This is almost the same as the binary case above, but we have to use
|
||||
// scalbn and ilogb rather than ldexp and frexp, we also only extract
|
||||
// one Radix digit at a time which is terribly inefficient!
|
||||
//
|
||||
typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
|
||||
typename From::exponent_type e;
|
||||
typename component_type<number<To> >::type num, denom;
|
||||
number<From> val(from);
|
||||
e = ilogb(val);
|
||||
val = scalbn(val, -e);
|
||||
while(val)
|
||||
{
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
val = scalbn(val, 1);
|
||||
num *= Radix;
|
||||
num += ll;
|
||||
--e;
|
||||
}
|
||||
++e;
|
||||
denom = ui_type(Radix);
|
||||
denom = pow(denom, abs(e));
|
||||
if(e > 0)
|
||||
{
|
||||
num *= denom;
|
||||
denom = 1;
|
||||
}
|
||||
assign_components(to, num.backend(), denom.backend());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
||||
{
|
||||
generic_interconvert_float2rational(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
||||
{
|
||||
number<From> t(from);
|
||||
number<To> result(numerator(t) / denominator(t));
|
||||
to = result.backend();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<2>& /*radix*/)
|
||||
{
|
||||
typedef typename From::exponent_type exponent_type;
|
||||
static const exponent_type shift = std::numeric_limits<boost::long_long_type>::digits;
|
||||
exponent_type e;
|
||||
number<To> num(0u);
|
||||
number<From> val(from);
|
||||
val = frexp(val, &e);
|
||||
while(e > 0)
|
||||
{
|
||||
int s = (std::min)(e, shift);
|
||||
val = ldexp(val, s);
|
||||
e -= s;
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
num <<= s;
|
||||
num += ll;
|
||||
}
|
||||
to = num.backend();
|
||||
}
|
||||
|
||||
template <class To, class From, int Radix>
|
||||
void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<Radix>& /*radix*/)
|
||||
{
|
||||
//
|
||||
// This is almost the same as the binary case above, but we have to use
|
||||
// scalbn and ilogb rather than ldexp and frexp, we also only extract
|
||||
// one Radix digit at a time which is terribly inefficient!
|
||||
//
|
||||
typename From::exponent_type e;
|
||||
number<To> num(0u);
|
||||
number<From> val(from);
|
||||
e = ilogb(val);
|
||||
val = scalbn(val, -e);
|
||||
while(e >= 0)
|
||||
{
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
val = scalbn(val, 1);
|
||||
num *= Radix;
|
||||
num += ll;
|
||||
--e;
|
||||
}
|
||||
to = num.backend();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
||||
{
|
||||
generic_interconvert_float2int(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespaces
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MP_GENERIC_INTERCONVERT_HPP
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 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_
|
||||
|
||||
#ifndef BOOST_MP_INT_FUNC_HPP
|
||||
#define BOOST_MP_INT_FUNC_HPP
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace default_ops
|
||||
{
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r)
|
||||
{
|
||||
eval_divide(q, x, y);
|
||||
eval_modulus(r, x, y);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
inline Integer eval_integer_modulus(const Backend& x, Integer val)
|
||||
{
|
||||
BOOST_MP_USING_ABS
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_convert_to;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type int_type;
|
||||
Backend t;
|
||||
eval_modulus(t, x, static_cast<int_type>(val));
|
||||
Integer result;
|
||||
eval_convert_to(&result, t);
|
||||
return abs(result);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
|
||||
template <class B>
|
||||
inline void eval_gcd(B& result, const B& a, const B& b)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
int shift;
|
||||
|
||||
B u(a), v(b);
|
||||
|
||||
int s = eval_get_sign(u);
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if(s < 0)
|
||||
{
|
||||
u.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
s = eval_get_sign(v);
|
||||
if(s < 0)
|
||||
{
|
||||
v.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
|
||||
unsigned us = eval_lsb(u);
|
||||
unsigned vs = eval_lsb(v);
|
||||
shift = (std::min)(us, vs);
|
||||
eval_right_shift(u, us);
|
||||
eval_right_shift(v, vs);
|
||||
|
||||
do
|
||||
{
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
s = u.compare(v);
|
||||
if(s > 0)
|
||||
u.swap(v);
|
||||
if(s == 0)
|
||||
break;
|
||||
eval_subtract(v, u);
|
||||
vs = eval_lsb(v);
|
||||
eval_right_shift(v, vs);
|
||||
}
|
||||
while(true);
|
||||
|
||||
result = u;
|
||||
eval_left_shift(result, shift);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class B>
|
||||
inline void eval_lcm(B& result, const B& a, const B& b)
|
||||
{
|
||||
typedef typename mpl::front<typename B::unsigned_types>::type ui_type;
|
||||
B t;
|
||||
eval_gcd(t, a, b);
|
||||
|
||||
if(eval_is_zero(t))
|
||||
{
|
||||
result = static_cast<ui_type>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_divide(result, a, t);
|
||||
eval_multiply(result, b);
|
||||
}
|
||||
if(eval_get_sign(result) < 0)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const number<Backend, ExpressionTemplates>& x, const number<Backend, ExpressionTemplates>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
using default_ops::eval_qr;
|
||||
eval_qr(x.backend(), y.backend(), q.backend(), r.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const number<Backend, ExpressionTemplates>& x, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
divide_qr(x, number<Backend, ExpressionTemplates>(y), q, r);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const number<Backend, ExpressionTemplates>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
divide_qr(number<Backend, ExpressionTemplates>(x), y, q, r);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
divide_qr(number<Backend, ExpressionTemplates>(x), number<Backend, ExpressionTemplates>(y), q, r);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Integer>
|
||||
inline typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<Backend>::value == number_kind_integer> >, Integer>::type
|
||||
integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
|
||||
{
|
||||
using default_ops::eval_integer_modulus;
|
||||
return eval_integer_modulus(x.backend(), val);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Integer>
|
||||
inline typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer> >, Integer>::type
|
||||
integer_modulus(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, Integer val)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type result_type;
|
||||
return integer_modulus(result_type(x), val);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
|
||||
lsb(const number<Backend, ExpressionTemplates>& x)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
return eval_lsb(x.backend());
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
|
||||
lsb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
||||
number_type n(x);
|
||||
using default_ops::eval_lsb;
|
||||
return eval_lsb(n.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
|
||||
msb(const number<Backend, ExpressionTemplates>& x)
|
||||
{
|
||||
using default_ops::eval_msb;
|
||||
return eval_msb(x.backend());
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
|
||||
msb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
||||
number_type n(x);
|
||||
using default_ops::eval_msb;
|
||||
return eval_msb(n.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, bool>::type
|
||||
bit_test(const number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_test;
|
||||
return eval_bit_test(x.backend(), index);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, bool>::type
|
||||
bit_test(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, unsigned index)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
||||
number_type n(x);
|
||||
using default_ops::eval_bit_test;
|
||||
return eval_bit_test(n.backend(), index);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
||||
bit_set(number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_set;
|
||||
eval_bit_set(x.backend(), index);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
||||
bit_unset(number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_unset;
|
||||
eval_bit_unset(x.backend(), index);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
||||
bit_flip(number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_flip;
|
||||
eval_bit_flip(x.backend(), index);
|
||||
return x;
|
||||
}
|
||||
|
||||
namespace default_ops{
|
||||
|
||||
//
|
||||
// Within powm, we need a type with twice as many digits as the argument type, define
|
||||
// a traits class to obtain that type:
|
||||
//
|
||||
template <class Backend>
|
||||
struct double_precision_type
|
||||
{
|
||||
typedef Backend type;
|
||||
};
|
||||
|
||||
//
|
||||
// If the exponent is a signed integer type, then we need to
|
||||
// check the value is positive:
|
||||
//
|
||||
template <class Backend>
|
||||
inline void check_sign_of_backend(const Backend& v, const mpl::true_)
|
||||
{
|
||||
if(eval_get_sign(v) < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
}
|
||||
template <class Backend>
|
||||
inline void check_sign_of_backend(const Backend&, const mpl::false_){}
|
||||
//
|
||||
// Calculate (a^p)%c:
|
||||
//
|
||||
template <class Backend>
|
||||
void eval_powm(Backend& result, const Backend& a, const Backend& p, const Backend& c)
|
||||
{
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
|
||||
check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
|
||||
|
||||
double_type x, y(a), b(p), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(eval_get_sign(b) > 0)
|
||||
{
|
||||
if(eval_bit_test(b, 0))
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, c);
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, c);
|
||||
eval_right_shift(b, ui_type(1));
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, c);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
void eval_powm(Backend& result, const Backend& a, const Backend& p, Integer c)
|
||||
{
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer, double_type>::type i1_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type i2_type;
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
|
||||
|
||||
if(eval_get_sign(p) < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
|
||||
double_type x, y(a), b(p), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(eval_get_sign(b) > 0)
|
||||
{
|
||||
if(eval_bit_test(b, 0))
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, static_cast<i1_type>(c));
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, static_cast<i1_type>(c));
|
||||
eval_right_shift(b, ui_type(1));
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, static_cast<i2_type>(c));
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
typename enable_if<is_unsigned<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
|
||||
{
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
double_type x, y(a), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(b > 0)
|
||||
{
|
||||
if(b & 1)
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, c);
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, c);
|
||||
b >>= 1;
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, c);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
typename enable_if<is_signed<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
|
||||
{
|
||||
if(b < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
eval_powm(result, a, static_cast<typename make_unsigned<Integer>::type>(b), c);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer1, class Integer2>
|
||||
typename enable_if<is_unsigned<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
|
||||
{
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer1, double_type>::type i1_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer2, Backend>::type i2_type;
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
double_type x, y(a), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(b > 0)
|
||||
{
|
||||
if(b & 1)
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, static_cast<i1_type>(c));
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, static_cast<i1_type>(c));
|
||||
b >>= 1;
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, static_cast<i2_type>(c));
|
||||
}
|
||||
|
||||
template <class Backend, class Integer1, class Integer2>
|
||||
typename enable_if<is_signed<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
|
||||
{
|
||||
if(b < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
eval_powm(result, a, static_cast<typename make_unsigned<Integer1>::type>(b), c);
|
||||
}
|
||||
|
||||
struct powm_func
|
||||
{
|
||||
template <class T, class U, class V>
|
||||
void operator()(T& result, const T& b, const U& p, const V& m)const
|
||||
{
|
||||
eval_powm(result, b, p, m);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class T, class U, class V>
|
||||
inline typename enable_if<
|
||||
mpl::and_<
|
||||
mpl::bool_<number_category<T>::value == number_kind_integer>,
|
||||
mpl::or_<
|
||||
is_number<T>,
|
||||
is_number_expression<T>
|
||||
>,
|
||||
mpl::or_<
|
||||
is_number<U>,
|
||||
is_number_expression<U>,
|
||||
is_integral<U>
|
||||
>,
|
||||
mpl::or_<
|
||||
is_number<V>,
|
||||
is_number_expression<V>,
|
||||
is_integral<V>
|
||||
>
|
||||
>,
|
||||
typename mpl::if_<
|
||||
is_no_et_number<T>,
|
||||
T,
|
||||
typename mpl::if_<
|
||||
is_no_et_number<U>,
|
||||
U,
|
||||
typename mpl::if_<
|
||||
is_no_et_number<V>,
|
||||
V,
|
||||
detail::expression<detail::function, default_ops::powm_func, T, U, V> >::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
powm(const T& b, const U& p, const V& mod)
|
||||
{
|
||||
return detail::expression<detail::function, default_ops::powm_func, T, U, V>(
|
||||
default_ops::powm_func(), b, p, mod);
|
||||
}
|
||||
|
||||
}} //namespaces
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2016 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_MP_MIN_MAX_HPP
|
||||
#define BOOST_MP_MIN_MAX_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/is_backend.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
//
|
||||
// Expression template overloads for (min) and (max):
|
||||
//
|
||||
// Introduced in response to https://svn.boost.org/trac/boost/ticket/11149
|
||||
// note that these can not legally be injected into namespace std, and that doing so
|
||||
// may break future enhancements to the standard. None the less adding
|
||||
// namespace std{ using boost::multiprecision::(min); using boost::multiprecision::(max); }
|
||||
// to your code may get some generic code working that wouldn't work otherwise.
|
||||
//
|
||||
// The use of enable_if on the return type is to avoid poisoning std::min/max,
|
||||
// otherwise attempting to make an explicit call to min<long>(a, b) when these and std
|
||||
// versions are in scope, will cause the compiler to try to instantiate the signatures
|
||||
// for our versions as well as the std ones, which in turn instantiates number<long>
|
||||
// which fails to compile as "long" is not a valid backend type.
|
||||
//
|
||||
template <class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on>&>::type
|
||||
(min)(const number<Backend, et_on>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
template <class Backend, class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(min)(const number<Backend, et_on>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
number<Backend, et_on> t(b);
|
||||
if(a < t)
|
||||
return a;
|
||||
return BOOST_MP_MOVE(t);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(min)(const detail::expression<tag, A1, A2, A3, A4>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
number<Backend, et_on> t(a);
|
||||
if(t < b)
|
||||
return BOOST_MP_MOVE(t);
|
||||
return b;
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type
|
||||
(min)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 < t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type (min)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 < t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on>&>::type
|
||||
(max)(const number<Backend, et_on>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
template <class Backend, class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(max)(const number<Backend, et_on>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
number<Backend, et_on> t(b);
|
||||
if(a > t)
|
||||
return a;
|
||||
return BOOST_MP_MOVE(t);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(max)(const detail::expression<tag, A1, A2, A3, A4>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
number<Backend, et_on> t(a);
|
||||
if(t > b)
|
||||
return BOOST_MP_MOVE(t);
|
||||
return b;
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type
|
||||
(max)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 > t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type (max)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 > t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,624 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 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_MP_NO_ET_OPS_HPP
|
||||
#define BOOST_MP_NO_ET_OPS_HPP
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4714)
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
|
||||
//
|
||||
// Operators for non-expression template enabled number.
|
||||
// NOTE: this is not a complete header - really just a suffix to default_ops.hpp.
|
||||
// NOTE: these operators have to be defined after the methods in default_ops.hpp.
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (const number<B, et_off>& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(is_signed_number<B>::value, "Negating an unsigned type results in ill-defined behavior.");
|
||||
number<B, et_off> result(v);
|
||||
result.backend().negate();
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator ~ (const number<B, et_off>& v)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
eval_complement(result.backend(), v.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// Addition:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// Subtraction:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator - (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator - (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// Multiply:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// divide:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator / (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator / (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator / (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// modulus:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator % (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator % (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator % (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// Bitwise or:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// Bitwise xor:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// Bitwise and:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(result.backend(), a.backend(), b.backend());
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
//
|
||||
// shifts:
|
||||
//
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator << (const number<B, et_off>& a, const I& b)
|
||||
{
|
||||
number<B, et_off> result(a);
|
||||
using default_ops::eval_left_shift;
|
||||
detail::check_shift_range(b, mpl::bool_<(sizeof(I) > sizeof(std::size_t))>(), is_signed<I>());
|
||||
eval_left_shift(result.backend(), b);
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator >> (const number<B, et_off>& a, const I& b)
|
||||
{
|
||||
number<B, et_off> result(a);
|
||||
using default_ops::eval_right_shift;
|
||||
detail::check_shift_range(b, mpl::bool_<(sizeof(I) > sizeof(std::size_t))>(), is_signed<I>());
|
||||
eval_right_shift(result.backend(), b);
|
||||
return BOOST_MP_MOVE(result);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !(defined(__GNUC__) && ((__GNUC__ == 4) && (__GNUC_MINOR__ < 5)))
|
||||
//
|
||||
// If we have rvalue references go all over again with rvalue ref overloads and move semantics.
|
||||
// Note that while it would be tempting to implement these so they return an rvalue reference
|
||||
// (and indeed this would be optimally efficient), this is unsafe due to users propensity to
|
||||
// write:
|
||||
//
|
||||
// const T& t = a * b;
|
||||
//
|
||||
// which would lead to a dangling reference if we didn't return by value. Of course move
|
||||
// semantics help a great deal in return by value, so performance is still pretty good...
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (number<B, et_off>&& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(is_signed_number<B>::value, "Negating an unsigned type results in ill-defined behavior.");
|
||||
v.backend().negate();
|
||||
return static_cast<number<B, et_off>&&>(v);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ~ (number<B, et_off>&& v)
|
||||
{
|
||||
eval_complement(v.backend(), v.backend());
|
||||
return static_cast<number<B, et_off>&&>(v);
|
||||
}
|
||||
//
|
||||
// Addition:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Subtraction:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_signed_number<B>, number<B, et_off> >::type operator - (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(b.backend(), a.backend());
|
||||
b.backend().negate();
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator - (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<(is_compatible_arithmetic_type<V, number<B, et_off> >::value && is_signed_number<B>::value), number<B, et_off> >::type
|
||||
operator - (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
b.backend().negate();
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Multiply:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// divide:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator / (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator / (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
//
|
||||
// modulus:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator % (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator % (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
//
|
||||
// Bitwise or:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Bitwise xor:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Bitwise and:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// shifts:
|
||||
//
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator << (number<B, et_off>&& a, const I& b)
|
||||
{
|
||||
using default_ops::eval_left_shift;
|
||||
eval_left_shift(a.backend(), b);
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator >> (number<B, et_off>&& a, const I& b)
|
||||
{
|
||||
using default_ops::eval_right_shift;
|
||||
eval_right_shift(a.backend(), b);
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MP_NO_ET_OPS_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,660 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 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_MP_COMPARE_HPP
|
||||
#define BOOST_MP_COMPARE_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/is_backend.hpp>
|
||||
|
||||
//
|
||||
// Comparison operators for number.
|
||||
//
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace default_ops{
|
||||
|
||||
//
|
||||
// The dispatching mechanism used here to deal with differently typed arguments
|
||||
// could be better replaced with enable_if overloads, but that breaks MSVC-12
|
||||
// under strange and hard to reproduce circumstances.
|
||||
//
|
||||
template <class B>
|
||||
inline bool eval_eq(const B& a, const B& b)
|
||||
{
|
||||
return a.compare(b) == 0;
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_eq_imp(const T& a, const U& b, const mpl::true_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
|
||||
return eval_eq(a, t.backend());
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_eq_imp(const T& a, const U& b, const mpl::false_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
|
||||
return eval_eq(t.backend(), b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_eq(const T& a, const U& b)
|
||||
{
|
||||
typedef mpl::bool_<boost::multiprecision::detail::is_first_backend<T, U>::value> tag_type;
|
||||
return eval_eq_imp(a, b, tag_type());
|
||||
}
|
||||
|
||||
template <class B>
|
||||
inline bool eval_lt(const B& a, const B& b)
|
||||
{
|
||||
return a.compare(b) < 0;
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_lt_imp(const T& a, const U& b, const mpl::true_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
|
||||
return eval_lt(a, t.backend());
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_lt_imp(const T& a, const U& b, const mpl::false_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
|
||||
return eval_lt(t.backend(), b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_lt(const T& a, const U& b)
|
||||
{
|
||||
typedef mpl::bool_<boost::multiprecision::detail::is_first_backend<T, U>::value> tag_type;
|
||||
return eval_lt_imp(a, b, tag_type());
|
||||
}
|
||||
|
||||
template <class B>
|
||||
inline bool eval_gt(const B& a, const B& b)
|
||||
{
|
||||
return a.compare(b) > 0;
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_gt_imp(const T& a, const U& b, const mpl::true_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
|
||||
return eval_gt(a, t.backend());
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_gt_imp(const T& a, const U& b, const mpl::false_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
|
||||
return eval_gt(t.backend(), b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_gt(const T& a, const U& b)
|
||||
{
|
||||
typedef mpl::bool_<boost::multiprecision::detail::is_first_backend<T, U>::value> tag_type;
|
||||
return eval_gt_imp(a, b, tag_type());
|
||||
}
|
||||
|
||||
} // namespace default_ops
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class Num, class Val>
|
||||
struct is_valid_mixed_compare : public mpl::false_ {};
|
||||
|
||||
template <class B, expression_template_option ET, class Val>
|
||||
struct is_valid_mixed_compare<number<B, ET>, Val> : public is_convertible<Val, number<B, ET> > {};
|
||||
|
||||
template <class B, expression_template_option ET>
|
||||
struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {};
|
||||
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline
|
||||
#if !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40700)
|
||||
BOOST_CONSTEXPR
|
||||
#endif
|
||||
typename boost::enable_if_c<number_category<Backend>::value == number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>& a)
|
||||
{
|
||||
using default_ops::eval_fpclassify;
|
||||
return eval_fpclassify(a.backend()) == FP_NAN;
|
||||
}
|
||||
|
||||
template <class Arithmetic>
|
||||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
template <class Arithmetic>
|
||||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a)
|
||||
{
|
||||
return (boost::math::isnan)(a);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b)
|
||||
{
|
||||
return is_unordered_value(a) || is_unordered_value(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator == (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_eq(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return eval_eq(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return eval_eq(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return eval_eq(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator != (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return true;
|
||||
return !eval_eq(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return true;
|
||||
return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return true;
|
||||
return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return true;
|
||||
return !eval_eq(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return true;
|
||||
return !eval_eq(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return true;
|
||||
return !eval_eq(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator < (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_lt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return eval_gt(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return eval_lt(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return eval_lt(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator > (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_gt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return a > t;
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return t > b;
|
||||
}
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return t > t2;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator <= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_gt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_value(a) || detail::is_unordered_value(b))
|
||||
return false;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return !eval_lt(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return !eval_gt(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return !eval_gt(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator >= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_lt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return !eval_gt(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return !eval_lt(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return !eval_lt(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
//
|
||||
// C99 comparison macros as functions:
|
||||
//
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a > b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a > b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a > b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a > b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a > b; }
|
||||
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a > b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a >= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a >= b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a >= b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a >= b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a >= b; }
|
||||
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a >= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a <= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a <= b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a <= b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a <= b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a <= b; }
|
||||
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a <= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isless BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a < b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a < b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a < b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a < b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a < b; }
|
||||
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a < b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return a != b;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return a != b;
|
||||
}
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return a != b;
|
||||
}
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type b(bb);
|
||||
return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(a, b);
|
||||
}
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const Arithmetic& b)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(a, b);
|
||||
}
|
||||
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type b(bb);
|
||||
return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(a, b);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return detail::is_unordered_comparison(a, b); }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return detail::is_unordered_comparison(a, b); }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return detail::is_unordered_comparison(a, b); }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type b(bb);
|
||||
return detail::is_unordered_comparison(a, b);
|
||||
}
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const Arithmetic& b)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
return detail::is_unordered_comparison(a, b);
|
||||
}
|
||||
|
||||
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<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type b(bb);
|
||||
return detail::is_unordered_comparison(a, b);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MP_COMPARE_HPP
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock.
|
||||
// Copyright Christopher Kormanyos 2013. 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_MP_DETAIL_REBIND_HPP
|
||||
#define BOOST_MP_DETAIL_REBIND_HPP
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace detail
|
||||
{
|
||||
template <class value_type, class my_allocator>
|
||||
struct rebind
|
||||
{
|
||||
typedef typename my_allocator::template rebind<value_type>::other type;
|
||||
};
|
||||
} } } } // namespace boost::multiprecision::backends::detail
|
||||
|
||||
#endif // BOOST_MP_DETAIL_REBIND_HPP
|
||||
@@ -0,0 +1,77 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 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_MP_UBLAS_HPP
|
||||
#define BOOST_MP_UBLAS_HPP
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
template<class V>
|
||||
class sparse_vector_element;
|
||||
|
||||
template <class V, class Backend, multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline bool operator == (const sparse_vector_element<V>& a, const ::boost::multiprecision::number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
typedef typename sparse_vector_element<V>::const_reference ref_type;
|
||||
return static_cast<ref_type>(a) == b;
|
||||
}
|
||||
|
||||
template<class X, class Y>
|
||||
struct promote_traits;
|
||||
|
||||
template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class Backend2, boost::multiprecision::expression_template_option ExpressionTemplates2>
|
||||
struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> number1_t;
|
||||
typedef boost::multiprecision::number<Backend2, ExpressionTemplates2> number2_t;
|
||||
typedef typename mpl::if_c<
|
||||
is_convertible<number1_t, number2_t>::value && !is_convertible<number2_t, number1_t>::value,
|
||||
number2_t, number1_t
|
||||
>::type promote_type;
|
||||
};
|
||||
|
||||
template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class Arithmetic>
|
||||
struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, Arithmetic>
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> promote_type;
|
||||
};
|
||||
|
||||
template <class Arithmetic, class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1>
|
||||
struct promote_traits<Arithmetic, boost::multiprecision::number<Backend1, ExpressionTemplates1> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> promote_type;
|
||||
};
|
||||
|
||||
template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> number1_t;
|
||||
typedef boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> expression_type;
|
||||
typedef typename expression_type::result_type number2_t;
|
||||
typedef typename promote_traits<number1_t, number2_t>::promote_type promote_type;
|
||||
};
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1>
|
||||
struct promote_traits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::number<Backend1, ExpressionTemplates1> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> number1_t;
|
||||
typedef boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> expression_type;
|
||||
typedef typename expression_type::result_type number2_t;
|
||||
typedef typename promote_traits<number1_t, number2_t>::promote_type promote_type;
|
||||
};
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tagb, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
struct promote_traits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::detail::expression<tagb, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
{
|
||||
typedef boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> expression1_t;
|
||||
typedef typename expression1_t::result_type number1_t;
|
||||
typedef boost::multiprecision::detail::expression<tagb, Arg1b, Arg2b, Arg3b, Arg4b> expression2_t;
|
||||
typedef typename expression2_t::result_type number2_t;
|
||||
};
|
||||
|
||||
}}} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock.
|
||||
// Copyright Christopher Kormanyos 2013. 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_MP_UTYPE_HELPER_HPP
|
||||
#define BOOST_MP_UTYPE_HELPER_HPP
|
||||
|
||||
#include <limits>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision {
|
||||
namespace detail
|
||||
{
|
||||
template<const unsigned> struct utype_helper { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<0U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<1U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<2U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<3U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<4U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<5U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<6U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<7U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<8U> { typedef boost::uint8_t exact; };
|
||||
|
||||
template<> struct utype_helper<9U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<10U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<11U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<12U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<13U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<14U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<15U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<16U> { typedef boost::uint16_t exact; };
|
||||
|
||||
template<> struct utype_helper<17U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<18U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<19U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<20U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<21U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<22U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<23U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<24U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<25U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<26U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<27U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<28U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<29U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<30U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<31U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<32U> { typedef boost::uint32_t exact; };
|
||||
|
||||
template<> struct utype_helper<33U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<34U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<35U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<36U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<37U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<38U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<39U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<40U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<41U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<42U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<43U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<44U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<45U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<46U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<47U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<48U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<49U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<50U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<51U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<52U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<53U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<54U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<55U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<56U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<57U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<58U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<59U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<60U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<61U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<62U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<63U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<64U> { typedef boost::uint64_t exact; };
|
||||
|
||||
template<class unsigned_type>
|
||||
int utype_prior(unsigned_type ui)
|
||||
{
|
||||
// TBD: Implement a templated binary search for this.
|
||||
int priority_bit;
|
||||
|
||||
unsigned_type priority_mask = unsigned_type(unsigned_type(1U) << (std::numeric_limits<unsigned_type>::digits - 1));
|
||||
|
||||
for(priority_bit = std::numeric_limits<unsigned_type>::digits - 1; priority_bit >= 0; --priority_bit)
|
||||
{
|
||||
if(unsigned_type(priority_mask & ui) != unsigned_type(0U))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
priority_mask >>= 1;
|
||||
}
|
||||
|
||||
return priority_bit;
|
||||
}
|
||||
|
||||
} } }
|
||||
|
||||
#endif // BOOST_MP_UTYPE_HELPER_HPP
|
||||
Reference in New Issue
Block a user