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