Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:24

0001 ///////////////////////////////////////////////////////////////////////////////
0002 //  Copyright 2018 John Maddock. Distributed under the Boost
0003 //  Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_MP_DETAIL_PRECISION_HPP
0007 #define BOOST_MP_DETAIL_PRECISION_HPP
0008 
0009 #include <boost/multiprecision/traits/is_variable_precision.hpp>
0010 #include <boost/multiprecision/detail/number_base.hpp>
0011 #include <boost/multiprecision/detail/digits.hpp>
0012 #include <boost/multiprecision/detail/assert.hpp>
0013 
0014 namespace boost { namespace multiprecision { namespace detail {
0015 
0016 template <class B, boost::multiprecision::expression_template_option ET>
0017 inline constexpr unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>&, const std::integral_constant<int, 0>&)
0018 {
0019    return std::numeric_limits<boost::multiprecision::number<B, ET> >::digits10;
0020 }
0021 template <class B, boost::multiprecision::expression_template_option ET>
0022 inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<int, 1>&)
0023 {
0024    //
0025    // We have an arbitrary precision integer, take it's "precision" as the
0026    // location of the most-significant-bit less the location of the
0027    // least-significant-bit, ie the number of bits required to represent the
0028    // the value assuming we will have an exponent to shift things by:
0029    //
0030    return static_cast<unsigned>(val.is_zero() ? 1 : 1 + digits2_2_10(msb(abs(val)) - lsb(abs(val)) + 1));
0031 }
0032 template <class B, boost::multiprecision::expression_template_option ET>
0033 inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_last_chance_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<int, 2>&)
0034 {
0035    //
0036    // We have an arbitrary precision rational, take it's "precision" as the
0037    // the larger of the "precision" of numerator and denominator:
0038    //
0039    return (std::max)(current_precision_of_last_chance_imp(numerator(val), std::integral_constant<int, 1>()), current_precision_of_last_chance_imp(denominator(val), std::integral_constant<int, 1>()));
0040 }
0041 
0042 template <class B, boost::multiprecision::expression_template_option ET>
0043 inline BOOST_MP_CXX14_CONSTEXPR unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& n, const std::integral_constant<bool, true>&)
0044 {
0045    return n.precision();
0046 }
0047 template <class B, boost::multiprecision::expression_template_option ET>
0048 inline constexpr unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& val, const std::integral_constant<bool, false>&)
0049 {
0050    using tag = std::integral_constant<int,
0051                                       std::numeric_limits<boost::multiprecision::number<B, ET> >::is_specialized &&
0052                                               std::numeric_limits<boost::multiprecision::number<B, ET> >::is_integer &&
0053                                               std::numeric_limits<boost::multiprecision::number<B, ET> >::is_exact &&
0054                                               !std::numeric_limits<boost::multiprecision::number<B, ET> >::is_modulo
0055                                           ? 1
0056                                       : boost::multiprecision::number_category<boost::multiprecision::number<B, ET> >::value == boost::multiprecision::number_kind_rational ? 2
0057                                                                                                                                                                             : 0>;
0058    return current_precision_of_last_chance_imp(val, tag());
0059 }
0060 
0061 template <class R, class Terminal>
0062 inline constexpr unsigned current_precision_of_terminal(const Terminal&)
0063 {
0064    return (R::thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision) 
0065       ? (std::numeric_limits<Terminal>::min_exponent ? std::numeric_limits<Terminal>::digits10 : 1 + std::numeric_limits<Terminal>::digits10) : 0;
0066 }
0067 template <class R, class Terminal>
0068 inline constexpr unsigned current_precision_of(const Terminal& r)
0069 {
0070    return current_precision_of_terminal<R>(R::canonical_value(r));
0071 }
0072 template <class R>
0073 inline constexpr unsigned current_precision_of(const float&)
0074 {
0075    using list = typename R::backend_type::float_types;
0076    using first_float = typename std::tuple_element<0, list>::type;
0077 
0078    return (R::thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision) ? std::numeric_limits<first_float>::digits10 : 0;
0079 }
0080 
0081 template <class R, class Terminal, std::size_t N>
0082 inline constexpr unsigned current_precision_of(const Terminal (&)[N])
0083 { // For string literals:
0084    return 0;
0085 }
0086 
0087 template <class R, class B, boost::multiprecision::expression_template_option ET>
0088 inline constexpr unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& n, const std::true_type&)
0089 {
0090    return std::is_same<R, boost::multiprecision::number<B, ET> >::value 
0091       || (std::is_same<typename R::value_type, boost::multiprecision::number<B, ET> >::value && (R::thread_default_variable_precision_options() >= variable_precision_options::preserve_component_precision))
0092       || (R::thread_default_variable_precision_options() >= variable_precision_options::preserve_all_precision) 
0093       ? current_precision_of_imp(n, boost::multiprecision::detail::is_variable_precision<boost::multiprecision::number<B, ET> >()) : 0;
0094 }
0095 template <class R, class B, boost::multiprecision::expression_template_option ET>
0096 inline constexpr unsigned current_precision_of_imp(const boost::multiprecision::number<B, ET>& n, const std::false_type&)
0097 {
0098    return std::is_same<R, boost::multiprecision::number<B, ET> >::value 
0099       || std::is_same<typename R::value_type, boost::multiprecision::number<B, ET> >::value
0100       ? current_precision_of_imp(n, boost::multiprecision::detail::is_variable_precision<boost::multiprecision::number<B, ET> >()) : 0;
0101 }
0102 
0103 template <class R, class B, boost::multiprecision::expression_template_option ET>
0104 inline constexpr unsigned current_precision_of(const boost::multiprecision::number<B, ET>& n)
0105 {
0106    return current_precision_of_imp<R>(n, boost::multiprecision::detail::is_variable_precision<R>());
0107 }
0108 
0109 template <class R, class tag, class Arg1>
0110 inline constexpr unsigned current_precision_of(const expression<tag, Arg1, void, void, void>& expr)
0111 {
0112    return current_precision_of<R>(expr.left_ref());
0113 }
0114 
0115 template <class R, class Arg1>
0116 inline constexpr unsigned current_precision_of(const expression<terminal, Arg1, void, void, void>& expr)
0117 {
0118    return current_precision_of<R>(expr.value());
0119 }
0120 
0121 template <class R, class tag, class Arg1, class Arg2>
0122 inline constexpr unsigned current_precision_of(const expression<tag, Arg1, Arg2, void, void>& expr)
0123 {
0124    return (std::max)(current_precision_of<R>(expr.left_ref()), current_precision_of<R>(expr.right_ref()));
0125 }
0126 
0127 template <class R, class tag, class Arg1, class Arg2, class Arg3>
0128 inline constexpr unsigned current_precision_of(const expression<tag, Arg1, Arg2, Arg3, void>& expr)
0129 {
0130    return (std::max)((std::max)(current_precision_of<R>(expr.left_ref()), current_precision_of<R>(expr.right_ref())), current_precision_of<R>(expr.middle_ref()));
0131 }
0132 
0133 #ifdef BOOST_MSVC
0134 #pragma warning(push)
0135 #pragma warning(disable : 4130)
0136 #endif
0137 
0138 template <class R, bool = boost::multiprecision::detail::is_variable_precision<R>::value>
0139 struct scoped_default_precision
0140 {
0141    template <class T>
0142    constexpr scoped_default_precision(const T&) {}
0143    template <class T, class U>
0144    constexpr scoped_default_precision(const T&, const U&) {}
0145    template <class T, class U, class V>
0146    constexpr scoped_default_precision(const T&, const U&, const V&) {}
0147 
0148    //
0149    // This function is never called: in C++17 it won't be compiled either:
0150    //
0151    unsigned precision() const
0152    {
0153       BOOST_MP_ASSERT("This function should never be called!!" == nullptr);
0154       return 0;
0155    }
0156 };
0157 
0158 #ifdef BOOST_MSVC
0159 #pragma warning(pop)
0160 #endif
0161 
0162 template <class R>
0163 struct scoped_default_precision<R, true>
0164 {
0165    template <class T>
0166    BOOST_MP_CXX14_CONSTEXPR scoped_default_precision(const T& a)
0167    {
0168       init(has_uniform_precision() ? R::thread_default_precision() : (std::max)(R::thread_default_precision(), current_precision_of<R>(a)));
0169    }
0170    template <class T, class U>
0171    BOOST_MP_CXX14_CONSTEXPR scoped_default_precision(const T& a, const U& b)
0172    {
0173       init(has_uniform_precision() ? R::thread_default_precision() : (std::max)(R::thread_default_precision(), (std::max)(current_precision_of<R>(a), current_precision_of<R>(b))));
0174    }
0175    template <class T, class U, class V>
0176    BOOST_MP_CXX14_CONSTEXPR scoped_default_precision(const T& a, const U& b, const V& c)
0177    {
0178       init(has_uniform_precision() ? R::thread_default_precision() : (std::max)((std::max)(current_precision_of<R>(a), current_precision_of<R>(b)), (std::max)(R::thread_default_precision(), current_precision_of<R>(c))));
0179    }
0180    ~scoped_default_precision()
0181    {
0182       if(m_new_prec != m_old_prec)
0183          R::thread_default_precision(m_old_prec);
0184    }
0185    BOOST_MP_CXX14_CONSTEXPR unsigned precision() const
0186    {
0187       return m_new_prec;
0188    }
0189 
0190    static constexpr bool has_uniform_precision()
0191    {
0192       return R::thread_default_variable_precision_options() <= boost::multiprecision::variable_precision_options::assume_uniform_precision;
0193    }
0194 
0195  private:
0196    BOOST_MP_CXX14_CONSTEXPR void init(unsigned p)
0197    {
0198       m_old_prec = R::thread_default_precision();
0199       if (p && (p != m_old_prec))
0200       {
0201          R::thread_default_precision(p);
0202          m_new_prec = p;
0203       }
0204       else
0205          m_new_prec = m_old_prec;
0206    }
0207    unsigned m_old_prec, m_new_prec;
0208 };
0209 
0210 template <class T>
0211 inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T*, const std::integral_constant<bool, false>&) {}
0212 
0213 template <class T>
0214 inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T* obj, const std::integral_constant<bool, true>&)
0215 {
0216    if (obj->precision() != T::thread_default_precision())
0217    {
0218       obj->precision(T::thread_default_precision());
0219    }
0220 }
0221 
0222 template <class T>
0223 inline BOOST_MP_CXX14_CONSTEXPR void maybe_promote_precision(T* obj)
0224 {
0225    maybe_promote_precision(obj, std::integral_constant<bool, boost::multiprecision::detail::is_variable_precision<T>::value>());
0226 }
0227 
0228 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
0229 #define BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(T) \
0230    if                                               \
0231    constexpr(boost::multiprecision::detail::is_variable_precision<T>::value)
0232 #else
0233 #define BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(T) if (boost::multiprecision::detail::is_variable_precision<T>::value)
0234 #endif
0235 
0236 template <class T, bool = boost::multiprecision::detail::is_variable_precision<T>::value>
0237 struct scoped_target_precision
0238 {
0239    variable_precision_options opts;
0240    scoped_target_precision() : opts(T::thread_default_variable_precision_options())
0241    {
0242       T::thread_default_variable_precision_options(variable_precision_options::preserve_target_precision);
0243    }
0244    ~scoped_target_precision()
0245    {
0246       T::thread_default_variable_precision_options(opts);
0247    }
0248 };
0249 template <class T>
0250 struct scoped_target_precision<T, false> {};
0251 
0252 template <class T, bool = boost::multiprecision::detail::is_variable_precision<T>::value>
0253 struct scoped_source_precision
0254 {
0255    variable_precision_options opts;
0256    scoped_source_precision() : opts(T::thread_default_variable_precision_options())
0257    {
0258       T::thread_default_variable_precision_options(variable_precision_options::preserve_source_precision);
0259    }
0260    ~scoped_source_precision()
0261    {
0262       T::thread_default_variable_precision_options(opts);
0263    }
0264 };
0265 template <class T>
0266 struct scoped_source_precision<T, false> {};
0267 
0268 template <class T, bool = boost::multiprecision::detail::is_variable_precision<T>::value>
0269 struct scoped_precision_options
0270 {
0271    unsigned saved_digits;
0272    boost::multiprecision::variable_precision_options saved_options;
0273 
0274    scoped_precision_options(unsigned digits) 
0275       : saved_digits(T::thread_default_precision()), saved_options(T::thread_default_variable_precision_options())
0276    {
0277       T::thread_default_precision(digits);
0278    }
0279    scoped_precision_options(unsigned digits, variable_precision_options opts)
0280       : saved_digits(T::thread_default_precision()), saved_options(T::thread_default_variable_precision_options())
0281    {
0282       T::thread_default_precision(digits);
0283       T::thread_default_variable_precision_options(opts);
0284    }
0285    template <class U>
0286    scoped_precision_options(const U& u)
0287       : saved_digits(T::thread_default_precision()), saved_options(T::thread_default_variable_precision_options())
0288    {
0289       T::thread_default_precision(u.precision());
0290       T::thread_default_variable_precision_options(U::thread_default_variable_precision_options());
0291    }
0292    ~scoped_precision_options()
0293    {
0294       T::thread_default_variable_precision_options(saved_options);
0295       T::thread_default_precision(saved_digits);
0296    }
0297 };
0298 
0299 template <class T>
0300 struct scoped_precision_options<T, false>
0301 {
0302    scoped_precision_options(unsigned) {}
0303    scoped_precision_options(unsigned, variable_precision_options) {}
0304    template <class U>
0305    scoped_precision_options(const U&) {}
0306    ~scoped_precision_options() {}
0307 };
0308 
0309 }
0310 }
0311 } // namespace boost::multiprecision::detail
0312 
0313 #endif // BOOST_MP_DETAIL_PRECISION_HPP