File indexing completed on 2025-01-18 09:42:24
0001
0002
0003
0004
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
0026
0027
0028
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
0037
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 {
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
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 }
0312
0313 #endif