File indexing completed on 2025-01-30 09:49:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_NUMERIC_INTERVAL_ARITH2_HPP
0015 #define BOOST_NUMERIC_INTERVAL_ARITH2_HPP
0016
0017 #include <boost/config.hpp>
0018 #include <boost/numeric/interval/detail/interval_prototype.hpp>
0019 #include <boost/numeric/interval/detail/test_input.hpp>
0020 #include <boost/numeric/interval/detail/bugs.hpp>
0021 #include <boost/numeric/interval/detail/division.hpp>
0022 #include <boost/numeric/interval/arith.hpp>
0023 #include <boost/numeric/interval/policies.hpp>
0024 #include <algorithm>
0025 #include <cassert>
0026 #include <boost/config/no_tr1/cmath.hpp>
0027
0028 namespace boost {
0029 namespace numeric {
0030
0031 template<class T, class Policies> inline
0032 interval<T, Policies> fmod(const interval<T, Policies>& x,
0033 const interval<T, Policies>& y)
0034 {
0035 if (interval_lib::detail::test_input(x, y))
0036 return interval<T, Policies>::empty();
0037 typename Policies::rounding rnd;
0038 typedef typename interval_lib::unprotect<interval<T, Policies> >::type I;
0039 T const &yb = interval_lib::user::is_neg(x.lower()) ? y.lower() : y.upper();
0040 T n = rnd.int_down(rnd.div_down(x.lower(), yb));
0041 return (const I&)x - n * (const I&)y;
0042 }
0043
0044 template<class T, class Policies> inline
0045 interval<T, Policies> fmod(const interval<T, Policies>& x, const T& y)
0046 {
0047 if (interval_lib::detail::test_input(x, y))
0048 return interval<T, Policies>::empty();
0049 typename Policies::rounding rnd;
0050 typedef typename interval_lib::unprotect<interval<T, Policies> >::type I;
0051 T n = rnd.int_down(rnd.div_down(x.lower(), y));
0052 return (const I&)x - n * I(y);
0053 }
0054
0055 template<class T, class Policies> inline
0056 interval<T, Policies> fmod(const T& x, const interval<T, Policies>& y)
0057 {
0058 if (interval_lib::detail::test_input(x, y))
0059 return interval<T, Policies>::empty();
0060 typename Policies::rounding rnd;
0061 typedef typename interval_lib::unprotect<interval<T, Policies> >::type I;
0062 T const &yb = interval_lib::user::is_neg(x) ? y.lower() : y.upper();
0063 T n = rnd.int_down(rnd.div_down(x, yb));
0064 return x - n * (const I&)y;
0065 }
0066
0067 namespace interval_lib {
0068
0069 template<class T, class Policies> inline
0070 interval<T, Policies> division_part1(const interval<T, Policies>& x,
0071 const interval<T, Policies>& y, bool& b)
0072 {
0073 typedef interval<T, Policies> I;
0074 b = false;
0075 if (detail::test_input(x, y))
0076 return I::empty();
0077 if (zero_in(y))
0078 if (!user::is_zero(y.lower()))
0079 if (!user::is_zero(y.upper()))
0080 return detail::div_zero_part1(x, y, b);
0081 else
0082 return detail::div_negative(x, y.lower());
0083 else
0084 if (!user::is_zero(y.upper()))
0085 return detail::div_positive(x, y.upper());
0086 else
0087 return I::empty();
0088 else
0089 return detail::div_non_zero(x, y);
0090 }
0091
0092 template<class T, class Policies> inline
0093 interval<T, Policies> division_part2(const interval<T, Policies>& x,
0094 const interval<T, Policies>& y, bool b = true)
0095 {
0096 if (!b) return interval<T, Policies>::empty();
0097 return detail::div_zero_part2(x, y);
0098 }
0099
0100 template<class T, class Policies> inline
0101 interval<T, Policies> multiplicative_inverse(const interval<T, Policies>& x)
0102 {
0103 typedef interval<T, Policies> I;
0104 if (detail::test_input(x))
0105 return I::empty();
0106 T one = static_cast<T>(1);
0107 typename Policies::rounding rnd;
0108 if (zero_in(x)) {
0109 typedef typename Policies::checking checking;
0110 if (!user::is_zero(x.lower()))
0111 if (!user::is_zero(x.upper()))
0112 return I::whole();
0113 else
0114 return I(checking::neg_inf(), rnd.div_up(one, x.lower()), true);
0115 else
0116 if (!user::is_zero(x.upper()))
0117 return I(rnd.div_down(one, x.upper()), checking::pos_inf(), true);
0118 else
0119 return I::empty();
0120 } else
0121 return I(rnd.div_down(one, x.upper()), rnd.div_up(one, x.lower()), true);
0122 }
0123
0124 namespace detail {
0125
0126 template<class T, class Rounding> inline
0127 T pow_dn(const T& x_, int pwr, Rounding& rnd)
0128 {
0129 T x = x_;
0130 T y = (pwr & 1) ? x_ : static_cast<T>(1);
0131 pwr >>= 1;
0132 while (pwr > 0) {
0133 x = rnd.mul_down(x, x);
0134 if (pwr & 1) y = rnd.mul_down(x, y);
0135 pwr >>= 1;
0136 }
0137 return y;
0138 }
0139
0140 template<class T, class Rounding> inline
0141 T pow_up(const T& x_, int pwr, Rounding& rnd)
0142 {
0143 T x = x_;
0144 T y = (pwr & 1) ? x_ : static_cast<T>(1);
0145 pwr >>= 1;
0146 while (pwr > 0) {
0147 x = rnd.mul_up(x, x);
0148 if (pwr & 1) y = rnd.mul_up(x, y);
0149 pwr >>= 1;
0150 }
0151 return y;
0152 }
0153
0154 }
0155 }
0156
0157 template<class T, class Policies> inline
0158 interval<T, Policies> pow(const interval<T, Policies>& x, int pwr)
0159 {
0160 BOOST_USING_STD_MAX();
0161 using interval_lib::detail::pow_dn;
0162 using interval_lib::detail::pow_up;
0163 typedef interval<T, Policies> I;
0164
0165 if (interval_lib::detail::test_input(x))
0166 return I::empty();
0167
0168 if (pwr == 0)
0169 if (interval_lib::user::is_zero(x.lower())
0170 && interval_lib::user::is_zero(x.upper()))
0171 return I::empty();
0172 else
0173 return I(static_cast<T>(1));
0174 else if (pwr < 0)
0175 return interval_lib::multiplicative_inverse(pow(x, -pwr));
0176
0177 typename Policies::rounding rnd;
0178
0179 if (interval_lib::user::is_neg(x.upper())) {
0180 T yl = pow_dn(static_cast<T>(-x.upper()), pwr, rnd);
0181 T yu = pow_up(static_cast<T>(-x.lower()), pwr, rnd);
0182 if (pwr & 1)
0183 return I(-yu, -yl, true);
0184 else
0185 return I(yl, yu, true);
0186 } else if (interval_lib::user::is_neg(x.lower())) {
0187 if (pwr & 1) {
0188 return I(-pow_up(static_cast<T>(-x.lower()), pwr, rnd), pow_up(x.upper(), pwr, rnd), true);
0189 } else {
0190 return I(static_cast<T>(0), pow_up(max BOOST_PREVENT_MACRO_SUBSTITUTION(static_cast<T>(-x.lower()), x.upper()), pwr, rnd), true);
0191 }
0192 } else {
0193 return I(pow_dn(x.lower(), pwr, rnd), pow_up(x.upper(), pwr, rnd), true);
0194 }
0195 }
0196
0197 template<class T, class Policies> inline
0198 interval<T, Policies> sqrt(const interval<T, Policies>& x)
0199 {
0200 typedef interval<T, Policies> I;
0201 if (interval_lib::detail::test_input(x) || interval_lib::user::is_neg(x.upper()))
0202 return I::empty();
0203 typename Policies::rounding rnd;
0204 T l = !interval_lib::user::is_pos(x.lower()) ? static_cast<T>(0) : rnd.sqrt_down(x.lower());
0205 return I(l, rnd.sqrt_up(x.upper()), true);
0206 }
0207
0208 template<class T, class Policies> inline
0209 interval<T, Policies> square(const interval<T, Policies>& x)
0210 {
0211 typedef interval<T, Policies> I;
0212 if (interval_lib::detail::test_input(x))
0213 return I::empty();
0214 typename Policies::rounding rnd;
0215 const T& xl = x.lower();
0216 const T& xu = x.upper();
0217 if (interval_lib::user::is_neg(xu))
0218 return I(rnd.mul_down(xu, xu), rnd.mul_up(xl, xl), true);
0219 else if (interval_lib::user::is_pos(x.lower()))
0220 return I(rnd.mul_down(xl, xl), rnd.mul_up(xu, xu), true);
0221 else
0222 return I(static_cast<T>(0), (-xl > xu ? rnd.mul_up(xl, xl) : rnd.mul_up(xu, xu)), true);
0223 }
0224
0225 namespace interval_lib {
0226 namespace detail {
0227
0228 template< class I > inline
0229 I root_aux(typename I::base_type const &x, int k)
0230 {
0231 typedef typename I::base_type T;
0232 T tk(k);
0233 I y(static_cast<T>(1), x, true);
0234 for(;;) {
0235 T y0 = median(y);
0236 I yy = intersect(y, y0 - (pow(I(y0, y0, true), k) - x) / (tk * pow(y, k - 1)));
0237 if (equal(y, yy)) return y;
0238 y = yy;
0239 }
0240 }
0241
0242 template< class I > inline
0243 typename I::base_type root_aux_dn(typename I::base_type const &x, int k)
0244 {
0245 typedef typename I::base_type T;
0246 typedef typename I::traits_type Policies;
0247 typename Policies::rounding rnd;
0248 T one(1);
0249 if (x > one) return root_aux<I>(x, k).lower();
0250 if (x == one) return one;
0251 return rnd.div_down(one, root_aux<I>(rnd.div_up(one, x), k).upper());
0252 }
0253
0254 template< class I > inline
0255 typename I::base_type root_aux_up(typename I::base_type const &x, int k)
0256 {
0257 typedef typename I::base_type T;
0258 typedef typename I::traits_type Policies;
0259 typename Policies::rounding rnd;
0260 T one(1);
0261 if (x > one) return root_aux<I>(x, k).upper();
0262 if (x == one) return one;
0263 return rnd.div_up(one, root_aux<I>(rnd.div_down(one, x), k).lower());
0264 }
0265
0266 }
0267 }
0268
0269 template< class T, class Policies > inline
0270 interval<T, Policies> nth_root(interval<T, Policies> const &x, int k)
0271 {
0272 typedef interval<T, Policies> I;
0273 if (interval_lib::detail::test_input(x)) return I::empty();
0274 assert(k > 0);
0275 if (k == 1) return x;
0276 typedef typename interval_lib::unprotect<I>::type R;
0277 if (!interval_lib::user::is_pos(x.upper())) {
0278 if (interval_lib::user::is_zero(x.upper())) {
0279 T zero(0);
0280 if (!(k & 1) || interval_lib::user::is_zero(x.lower()))
0281 return I(zero, zero, true);
0282 else
0283 return I(-interval_lib::detail::root_aux_up<R>(-x.lower(), k), zero, true);
0284 } else if (!(k & 1))
0285 return I::empty();
0286 else {
0287 return I(-interval_lib::detail::root_aux_up<R>(-x.lower(), k),
0288 -interval_lib::detail::root_aux_dn<R>(-x.upper(), k), true);
0289 }
0290 }
0291 T u = interval_lib::detail::root_aux_up<R>(x.upper(), k);
0292 if (!interval_lib::user::is_pos(x.lower()))
0293 if (!(k & 1) || interval_lib::user::is_zero(x.lower()))
0294 return I(static_cast<T>(0), u, true);
0295 else
0296 return I(-interval_lib::detail::root_aux_up<R>(-x.lower(), k), u, true);
0297 else
0298 return I(interval_lib::detail::root_aux_dn<R>(x.lower(), k), u, true);
0299 }
0300
0301 }
0302 }
0303
0304 #endif