/////////////////////////////////////////////////////////////////////////////// // Copyright 2018 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_PRECISION_HPP #define BOOST_MP_PRECISION_HPP #include #include #include namespace boost { namespace multiprecision { namespace detail { template inline BOOST_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number&, const mpl::false_&) { return std::numeric_limits >::digits10; } template inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number& val, const mpl::true_&) { // // We have an arbitrary precision integer, take it's "precision" as the // location of the most-significant-bit less the location of the // least-significant-bit, ie the number of bits required to represent the // the value assuming we will have an exponent to shift things by: // return val.is_zero() ? 1 : digits2_2_10(msb(abs(val)) - lsb(abs(val)) + 1); } template inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_imp(const boost::multiprecision::number& n, const mpl::true_&) { return n.precision(); } template inline BOOST_CONSTEXPR unsigned current_precision_of_imp(const boost::multiprecision::number& val, const mpl::false_&) { return current_precision_of_last_chance_imp(val, mpl::bool_ < std::numeric_limits >::is_specialized && std::numeric_limits >::is_integer && std::numeric_limits >::is_exact && !std::numeric_limits >::is_modulo > ()); } template inline BOOST_CONSTEXPR unsigned current_precision_of(const Terminal&) { return std::numeric_limits::digits10; } template inline BOOST_CONSTEXPR unsigned current_precision_of(const Terminal (&)[N]) { // For string literals: return 0; } template inline BOOST_CONSTEXPR unsigned current_precision_of(const boost::multiprecision::number& n) { return current_precision_of_imp(n, boost::multiprecision::detail::is_variable_precision >()); } template inline BOOST_CONSTEXPR unsigned current_precision_of(const expression& expr) { return current_precision_of(expr.left_ref()); } template inline BOOST_CONSTEXPR unsigned current_precision_of(const expression& expr) { return current_precision_of(expr.value()); } template inline BOOST_CONSTEXPR unsigned current_precision_of(const expression& expr) { return (std::max)(current_precision_of(expr.left_ref()), current_precision_of(expr.right_ref())); } template inline BOOST_CONSTEXPR unsigned current_precision_of(const expression& expr) { return (std::max)((std::max)(current_precision_of(expr.left_ref()), current_precision_of(expr.right_ref())), current_precision_of(expr.middle_ref())); } #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable : 4130) #endif template ::value> struct scoped_default_precision { template BOOST_CONSTEXPR scoped_default_precision(const T&) {} template BOOST_CONSTEXPR scoped_default_precision(const T&, const U&) {} template BOOST_CONSTEXPR scoped_default_precision(const T&, const U&, const V&) {} // // This function is never called: in C++17 it won't be compiled either: // unsigned precision() const { BOOST_ASSERT("This function should never be called!!" == 0); return 0; } }; #ifdef BOOST_MSVC #pragma warning(pop) #endif template struct scoped_default_precision { template BOOST_MP_CXX14_CONSTEXPR scoped_default_precision(const T& a) { init(current_precision_of(a)); } template BOOST_MP_CXX14_CONSTEXPR scoped_default_precision(const T& a, const U& b) { init((std::max)(current_precision_of(a), current_precision_of(b))); } template BOOST_MP_CXX14_CONSTEXPR scoped_default_precision(const T& a, const U& b, const V& c) { init((std::max)((std::max)(current_precision_of(a), current_precision_of(b)), current_precision_of(c))); } ~scoped_default_precision() { R::default_precision(m_old_prec); } BOOST_MP_CXX14_CONSTEXPR unsigned precision() const { return m_new_prec; } private: BOOST_MP_CXX14_CONSTEXPR void init(unsigned p) { m_old_prec = R::default_precision(); if (p) { R::default_precision(p); m_new_prec = p; } else m_new_prec = m_old_prec; } unsigned m_old_prec, m_new_prec; }; template inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T*, const mpl::false_&) {} template inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T* obj, const mpl::true_&) { if (obj->precision() != T::default_precision()) { obj->precision(T::default_precision()); } } template inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T* obj) { maybe_promote_precision(obj, mpl::bool_::value>()); } #ifndef BOOST_NO_CXX17_IF_CONSTEXPR #define BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(T) \ if \ constexpr(boost::multiprecision::detail::is_variable_precision::value) #else #define BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(T) if (boost::multiprecision::detail::is_variable_precision::value) #endif } } } // namespace boost::multiprecision::detail #endif // BOOST_MP_IS_BACKEND_HPP