• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Boost interval/arith.hpp template implementation file
2  *
3  * Copyright 2000 Jens Maurer
4  * Copyright 2002-2003 Hervé Brönnimann, Guillaume Melquiond, Sylvain Pion
5  *
6  * Distributed under the Boost Software License, Version 1.0.
7  * (See accompanying file LICENSE_1_0.txt or
8  * copy at http://www.boost.org/LICENSE_1_0.txt)
9  */
10 
11 #ifndef BOOST_NUMERIC_INTERVAL_ARITH_HPP
12 #define BOOST_NUMERIC_INTERVAL_ARITH_HPP
13 
14 #include <boost/config.hpp>
15 #include <boost/numeric/interval/interval.hpp>
16 #include <boost/numeric/interval/detail/bugs.hpp>
17 #include <boost/numeric/interval/detail/test_input.hpp>
18 #include <boost/numeric/interval/detail/division.hpp>
19 #include <algorithm>
20 
21 namespace boost {
22 namespace numeric {
23 
24 /*
25  * Basic arithmetic operators
26  */
27 
28 template<class T, class Policies> inline
operator +(const interval<T,Policies> & x)29 const interval<T, Policies>& operator+(const interval<T, Policies>& x)
30 {
31   return x;
32 }
33 
34 template<class T, class Policies> inline
operator -(const interval<T,Policies> & x)35 interval<T, Policies> operator-(const interval<T, Policies>& x)
36 {
37   if (interval_lib::detail::test_input(x))
38     return interval<T, Policies>::empty();
39   return interval<T, Policies>(-x.upper(), -x.lower(), true);
40 }
41 
42 template<class T, class Policies> inline
operator +=(const interval<T,Policies> & r)43 interval<T, Policies>& interval<T, Policies>::operator+=(const interval<T, Policies>& r)
44 {
45   if (interval_lib::detail::test_input(*this, r))
46     set_empty();
47   else {
48     typename Policies::rounding rnd;
49     set(rnd.add_down(low, r.low), rnd.add_up(up, r.up));
50   }
51   return *this;
52 }
53 
54 template<class T, class Policies> inline
operator +=(const T & r)55 interval<T, Policies>& interval<T, Policies>::operator+=(const T& r)
56 {
57   if (interval_lib::detail::test_input(*this, r))
58     set_empty();
59   else {
60     typename Policies::rounding rnd;
61     set(rnd.add_down(low, r), rnd.add_up(up, r));
62   }
63   return *this;
64 }
65 
66 template<class T, class Policies> inline
operator -=(const interval<T,Policies> & r)67 interval<T, Policies>& interval<T, Policies>::operator-=(const interval<T, Policies>& r)
68 {
69   if (interval_lib::detail::test_input(*this, r))
70     set_empty();
71   else {
72     typename Policies::rounding rnd;
73     set(rnd.sub_down(low, r.up), rnd.sub_up(up, r.low));
74   }
75   return *this;
76 }
77 
78 template<class T, class Policies> inline
operator -=(const T & r)79 interval<T, Policies>& interval<T, Policies>::operator-=(const T& r)
80 {
81   if (interval_lib::detail::test_input(*this, r))
82     set_empty();
83   else {
84     typename Policies::rounding rnd;
85     set(rnd.sub_down(low, r), rnd.sub_up(up, r));
86   }
87   return *this;
88 }
89 
90 template<class T, class Policies> inline
operator *=(const interval<T,Policies> & r)91 interval<T, Policies>& interval<T, Policies>::operator*=(const interval<T, Policies>& r)
92 {
93   return *this = *this * r;
94 }
95 
96 template<class T, class Policies> inline
operator *=(const T & r)97 interval<T, Policies>& interval<T, Policies>::operator*=(const T& r)
98 {
99   return *this = r * *this;
100 }
101 
102 template<class T, class Policies> inline
operator /=(const interval<T,Policies> & r)103 interval<T, Policies>& interval<T, Policies>::operator/=(const interval<T, Policies>& r)
104 {
105   return *this = *this / r;
106 }
107 
108 template<class T, class Policies> inline
operator /=(const T & r)109 interval<T, Policies>& interval<T, Policies>::operator/=(const T& r)
110 {
111   return *this = *this / r;
112 }
113 
114 template<class T, class Policies> inline
operator +(const interval<T,Policies> & x,const interval<T,Policies> & y)115 interval<T, Policies> operator+(const interval<T, Policies>& x,
116                                 const interval<T, Policies>& y)
117 {
118   if (interval_lib::detail::test_input(x, y))
119     return interval<T, Policies>::empty();
120   typename Policies::rounding rnd;
121   return interval<T,Policies>(rnd.add_down(x.lower(), y.lower()),
122                               rnd.add_up  (x.upper(), y.upper()), true);
123 }
124 
125 template<class T, class Policies> inline
operator +(const T & x,const interval<T,Policies> & y)126 interval<T, Policies> operator+(const T& x, const interval<T, Policies>& y)
127 {
128   if (interval_lib::detail::test_input(x, y))
129     return interval<T, Policies>::empty();
130   typename Policies::rounding rnd;
131   return interval<T,Policies>(rnd.add_down(x, y.lower()),
132                               rnd.add_up  (x, y.upper()), true);
133 }
134 
135 template<class T, class Policies> inline
operator +(const interval<T,Policies> & x,const T & y)136 interval<T, Policies> operator+(const interval<T, Policies>& x, const T& y)
137 { return y + x; }
138 
139 template<class T, class Policies> inline
operator -(const interval<T,Policies> & x,const interval<T,Policies> & y)140 interval<T, Policies> operator-(const interval<T, Policies>& x,
141                                 const interval<T, Policies>& y)
142 {
143   if (interval_lib::detail::test_input(x, y))
144     return interval<T, Policies>::empty();
145   typename Policies::rounding rnd;
146   return interval<T,Policies>(rnd.sub_down(x.lower(), y.upper()),
147                               rnd.sub_up  (x.upper(), y.lower()), true);
148 }
149 
150 template<class T, class Policies> inline
operator -(const T & x,const interval<T,Policies> & y)151 interval<T, Policies> operator-(const T& x, const interval<T, Policies>& y)
152 {
153   if (interval_lib::detail::test_input(x, y))
154     return interval<T, Policies>::empty();
155   typename Policies::rounding rnd;
156   return interval<T,Policies>(rnd.sub_down(x, y.upper()),
157                               rnd.sub_up  (x, y.lower()), true);
158 }
159 
160 template<class T, class Policies> inline
operator -(const interval<T,Policies> & x,const T & y)161 interval<T, Policies> operator-(const interval<T, Policies>& x, const T& y)
162 {
163   if (interval_lib::detail::test_input(x, y))
164     return interval<T, Policies>::empty();
165   typename Policies::rounding rnd;
166   return interval<T,Policies>(rnd.sub_down(x.lower(), y),
167                               rnd.sub_up  (x.upper(), y), true);
168 }
169 
170 template<class T, class Policies> inline
operator *(const interval<T,Policies> & x,const interval<T,Policies> & y)171 interval<T, Policies> operator*(const interval<T, Policies>& x,
172                                 const interval<T, Policies>& y)
173 {
174   BOOST_USING_STD_MIN();
175   BOOST_USING_STD_MAX();
176   typedef interval<T, Policies> I;
177   if (interval_lib::detail::test_input(x, y))
178     return I::empty();
179   typename Policies::rounding rnd;
180   const T& xl = x.lower();
181   const T& xu = x.upper();
182   const T& yl = y.lower();
183   const T& yu = y.upper();
184 
185   if (interval_lib::user::is_neg(xl))
186     if (interval_lib::user::is_pos(xu))
187       if (interval_lib::user::is_neg(yl))
188         if (interval_lib::user::is_pos(yu)) // M * M
189           return I(min BOOST_PREVENT_MACRO_SUBSTITUTION(rnd.mul_down(xl, yu), rnd.mul_down(xu, yl)),
190                    max BOOST_PREVENT_MACRO_SUBSTITUTION(rnd.mul_up  (xl, yl), rnd.mul_up  (xu, yu)), true);
191         else                    // M * N
192           return I(rnd.mul_down(xu, yl), rnd.mul_up(xl, yl), true);
193       else
194         if (interval_lib::user::is_pos(yu)) // M * P
195           return I(rnd.mul_down(xl, yu), rnd.mul_up(xu, yu), true);
196         else                    // M * Z
197           return I(static_cast<T>(0), static_cast<T>(0), true);
198     else
199       if (interval_lib::user::is_neg(yl))
200         if (interval_lib::user::is_pos(yu)) // N * M
201           return I(rnd.mul_down(xl, yu), rnd.mul_up(xl, yl), true);
202         else                    // N * N
203           return I(rnd.mul_down(xu, yu), rnd.mul_up(xl, yl), true);
204       else
205         if (interval_lib::user::is_pos(yu)) // N * P
206           return I(rnd.mul_down(xl, yu), rnd.mul_up(xu, yl), true);
207         else                    // N * Z
208           return I(static_cast<T>(0), static_cast<T>(0), true);
209   else
210     if (interval_lib::user::is_pos(xu))
211       if (interval_lib::user::is_neg(yl))
212         if (interval_lib::user::is_pos(yu)) // P * M
213           return I(rnd.mul_down(xu, yl), rnd.mul_up(xu, yu), true);
214         else                    // P * N
215           return I(rnd.mul_down(xu, yl), rnd.mul_up(xl, yu), true);
216       else
217         if (interval_lib::user::is_pos(yu)) // P * P
218           return I(rnd.mul_down(xl, yl), rnd.mul_up(xu, yu), true);
219         else                    // P * Z
220           return I(static_cast<T>(0), static_cast<T>(0), true);
221     else                        // Z * ?
222       return I(static_cast<T>(0), static_cast<T>(0), true);
223 }
224 
225 template<class T, class Policies> inline
operator *(const T & x,const interval<T,Policies> & y)226 interval<T, Policies> operator*(const T& x, const interval<T, Policies>& y)
227 {
228   typedef interval<T, Policies> I;
229   if (interval_lib::detail::test_input(x, y))
230     return I::empty();
231   typename Policies::rounding rnd;
232   const T& yl = y.lower();
233   const T& yu = y.upper();
234   // x is supposed not to be infinite
235   if (interval_lib::user::is_neg(x))
236     return I(rnd.mul_down(x, yu), rnd.mul_up(x, yl), true);
237   else if (interval_lib::user::is_zero(x))
238     return I(static_cast<T>(0), static_cast<T>(0), true);
239   else
240     return I(rnd.mul_down(x, yl), rnd.mul_up(x, yu), true);
241 }
242 
243 template<class T, class Policies> inline
operator *(const interval<T,Policies> & x,const T & y)244 interval<T, Policies> operator*(const interval<T, Policies>& x, const T& y)
245 { return y * x; }
246 
247 template<class T, class Policies> inline
operator /(const interval<T,Policies> & x,const interval<T,Policies> & y)248 interval<T, Policies> operator/(const interval<T, Policies>& x,
249                                 const interval<T, Policies>& y)
250 {
251   if (interval_lib::detail::test_input(x, y))
252     return interval<T, Policies>::empty();
253   if (zero_in(y))
254     if (!interval_lib::user::is_zero(y.lower()))
255       if (!interval_lib::user::is_zero(y.upper()))
256         return interval_lib::detail::div_zero(x);
257       else
258         return interval_lib::detail::div_negative(x, y.lower());
259     else
260       if (!interval_lib::user::is_zero(y.upper()))
261         return interval_lib::detail::div_positive(x, y.upper());
262       else
263         return interval<T, Policies>::empty();
264   else
265     return interval_lib::detail::div_non_zero(x, y);
266 }
267 
268 template<class T, class Policies> inline
operator /(const T & x,const interval<T,Policies> & y)269 interval<T, Policies> operator/(const T& x, const interval<T, Policies>& y)
270 {
271   if (interval_lib::detail::test_input(x, y))
272     return interval<T, Policies>::empty();
273   if (zero_in(y))
274     if (!interval_lib::user::is_zero(y.lower()))
275       if (!interval_lib::user::is_zero(y.upper()))
276         return interval_lib::detail::div_zero<T, Policies>(x);
277       else
278         return interval_lib::detail::div_negative<T, Policies>(x, y.lower());
279     else
280       if (!interval_lib::user::is_zero(y.upper()))
281         return interval_lib::detail::div_positive<T, Policies>(x, y.upper());
282       else
283         return interval<T, Policies>::empty();
284   else
285     return interval_lib::detail::div_non_zero(x, y);
286 }
287 
288 template<class T, class Policies> inline
operator /(const interval<T,Policies> & x,const T & y)289 interval<T, Policies> operator/(const interval<T, Policies>& x, const T& y)
290 {
291   if (interval_lib::detail::test_input(x, y) || interval_lib::user::is_zero(y))
292     return interval<T, Policies>::empty();
293   typename Policies::rounding rnd;
294   const T& xl = x.lower();
295   const T& xu = x.upper();
296   if (interval_lib::user::is_neg(y))
297     return interval<T, Policies>(rnd.div_down(xu, y), rnd.div_up(xl, y), true);
298   else
299     return interval<T, Policies>(rnd.div_down(xl, y), rnd.div_up(xu, y), true);
300 }
301 
302 } // namespace numeric
303 } // namespace boost
304 
305 #endif // BOOST_NUMERIC_INTERVAL_ARITH_HPP
306