1 /* Boost interval/detail/division.hpp file
2  *
3  * Copyright 2003 Guillaume Melquiond, Sylvain Pion
4  *
5  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE_1_0.txt or
7  * copy at http://www.boost.org/LICENSE_1_0.txt)
8  */
9 
10 #ifndef BOOST_NUMERIC_INTERVAL_DETAIL_DIVISION_HPP
11 #define BOOST_NUMERIC_INTERVAL_DETAIL_DIVISION_HPP
12 
13 #include <boost/numeric/interval/detail/interval_prototype.hpp>
14 #include <boost/numeric/interval/detail/bugs.hpp>
15 #include <boost/numeric/interval/detail/test_input.hpp>
16 #include <boost/numeric/interval/rounded_arith.hpp>
17 #include <algorithm>
18 
19 namespace boost {
20 namespace numeric {
21 namespace interval_lib {
22 namespace detail {
23 
24 template<class T, class Policies> inline
div_non_zero(const interval<T,Policies> & x,const interval<T,Policies> & y)25 interval<T, Policies> div_non_zero(const interval<T, Policies>& x,
26                                    const interval<T, Policies>& y)
27 {
28   // assert(!in_zero(y));
29   typename Policies::rounding rnd;
30   typedef interval<T, Policies> I;
31   const T& xl = x.lower();
32   const T& xu = x.upper();
33   const T& yl = y.lower();
34   const T& yu = y.upper();
35   if (::boost::numeric::interval_lib::user::is_neg(xu))
36     if (::boost::numeric::interval_lib::user::is_neg(yu))
37       return I(rnd.div_down(xu, yl), rnd.div_up(xl, yu), true);
38     else
39       return I(rnd.div_down(xl, yl), rnd.div_up(xu, yu), true);
40   else if (::boost::numeric::interval_lib::user::is_neg(xl))
41     if (::boost::numeric::interval_lib::user::is_neg(yu))
42       return I(rnd.div_down(xu, yu), rnd.div_up(xl, yu), true);
43     else
44       return I(rnd.div_down(xl, yl), rnd.div_up(xu, yl), true);
45   else
46     if (::boost::numeric::interval_lib::user::is_neg(yu))
47       return I(rnd.div_down(xu, yu), rnd.div_up(xl, yl), true);
48     else
49       return I(rnd.div_down(xl, yu), rnd.div_up(xu, yl), true);
50 }
51 
52 template<class T, class Policies> inline
div_non_zero(const T & x,const interval<T,Policies> & y)53 interval<T, Policies> div_non_zero(const T& x, const interval<T, Policies>& y)
54 {
55   // assert(!in_zero(y));
56   typename Policies::rounding rnd;
57   typedef interval<T, Policies> I;
58   const T& yl = y.lower();
59   const T& yu = y.upper();
60   if (::boost::numeric::interval_lib::user::is_neg(x))
61     return I(rnd.div_down(x, yl), rnd.div_up(x, yu), true);
62   else
63     return I(rnd.div_down(x, yu), rnd.div_up(x, yl), true);
64 }
65 
66 template<class T, class Policies> inline
div_positive(const interval<T,Policies> & x,const T & yu)67 interval<T, Policies> div_positive(const interval<T, Policies>& x, const T& yu)
68 {
69   // assert(::boost::numeric::interval_lib::user::is_pos(yu));
70   if (::boost::numeric::interval_lib::user::is_zero(x.lower()) &&
71       ::boost::numeric::interval_lib::user::is_zero(x.upper()))
72     return x;
73   typename Policies::rounding rnd;
74   typedef interval<T, Policies> I;
75   const T& xl = x.lower();
76   const T& xu = x.upper();
77   typedef typename Policies::checking checking;
78   if (::boost::numeric::interval_lib::user::is_neg(xu))
79     return I(checking::neg_inf(), rnd.div_up(xu, yu), true);
80   else if (::boost::numeric::interval_lib::user::is_neg(xl))
81     return I(checking::neg_inf(), checking::pos_inf(), true);
82   else
83     return I(rnd.div_down(xl, yu), checking::pos_inf(), true);
84 }
85 
86 template<class T, class Policies> inline
div_positive(const T & x,const T & yu)87 interval<T, Policies> div_positive(const T& x, const T& yu)
88 {
89   // assert(::boost::numeric::interval_lib::user::is_pos(yu));
90   typedef interval<T, Policies> I;
91   if (::boost::numeric::interval_lib::user::is_zero(x))
92     return I(static_cast<T>(0), static_cast<T>(0), true);
93   typename Policies::rounding rnd;
94   typedef typename Policies::checking checking;
95   if (::boost::numeric::interval_lib::user::is_neg(x))
96     return I(checking::neg_inf(), rnd.div_up(x, yu), true);
97   else
98     return I(rnd.div_down(x, yu), checking::pos_inf(), true);
99 }
100 
101 template<class T, class Policies> inline
div_negative(const interval<T,Policies> & x,const T & yl)102 interval<T, Policies> div_negative(const interval<T, Policies>& x, const T& yl)
103 {
104   // assert(::boost::numeric::interval_lib::user::is_neg(yl));
105   if (::boost::numeric::interval_lib::user::is_zero(x.lower()) &&
106       ::boost::numeric::interval_lib::user::is_zero(x.upper()))
107     return x;
108   typename Policies::rounding rnd;
109   typedef interval<T, Policies> I;
110   const T& xl = x.lower();
111   const T& xu = x.upper();
112   typedef typename Policies::checking checking;
113   if (::boost::numeric::interval_lib::user::is_neg(xu))
114     return I(rnd.div_down(xu, yl), checking::pos_inf(), true);
115   else if (::boost::numeric::interval_lib::user::is_neg(xl))
116     return I(checking::neg_inf(), checking::pos_inf(), true);
117   else
118     return I(checking::neg_inf(), rnd.div_up(xl, yl), true);
119 }
120 
121 template<class T, class Policies> inline
div_negative(const T & x,const T & yl)122 interval<T, Policies> div_negative(const T& x, const T& yl)
123 {
124   // assert(::boost::numeric::interval_lib::user::is_neg(yl));
125   typedef interval<T, Policies> I;
126   if (::boost::numeric::interval_lib::user::is_zero(x))
127     return I(static_cast<T>(0), static_cast<T>(0), true);
128   typename Policies::rounding rnd;
129   typedef typename Policies::checking checking;
130   if (::boost::numeric::interval_lib::user::is_neg(x))
131     return I(rnd.div_down(x, yl), checking::pos_inf(), true);
132   else
133     return I(checking::neg_inf(), rnd.div_up(x, yl), true);
134 }
135 
136 template<class T, class Policies> inline
div_zero(const interval<T,Policies> & x)137 interval<T, Policies> div_zero(const interval<T, Policies>& x)
138 {
139   if (::boost::numeric::interval_lib::user::is_zero(x.lower()) &&
140       ::boost::numeric::interval_lib::user::is_zero(x.upper()))
141     return x;
142   else return interval<T, Policies>::whole();
143 }
144 
145 template<class T, class Policies> inline
div_zero(const T & x)146 interval<T, Policies> div_zero(const T& x)
147 {
148   if (::boost::numeric::interval_lib::user::is_zero(x))
149     return interval<T, Policies>(static_cast<T>(0), static_cast<T>(0), true);
150   else return interval<T, Policies>::whole();
151 }
152 
153 template<class T, class Policies> inline
div_zero_part1(const interval<T,Policies> & x,const interval<T,Policies> & y,bool & b)154 interval<T, Policies> div_zero_part1(const interval<T, Policies>& x,
155                                      const interval<T, Policies>& y, bool& b)
156 {
157   // assert(::boost::numeric::interval_lib::user::is_neg(y.lower()) && ::boost::numeric::interval_lib::user::is_pos(y.upper()));
158   if (::boost::numeric::interval_lib::user::is_zero(x.lower()) && ::boost::numeric::interval_lib::user::is_zero(x.upper()))
159     { b = false; return x; }
160   typename Policies::rounding rnd;
161   typedef interval<T, Policies> I;
162   const T& xl = x.lower();
163   const T& xu = x.upper();
164   const T& yl = y.lower();
165   const T& yu = y.upper();
166   typedef typename Policies::checking checking;
167   if (::boost::numeric::interval_lib::user::is_neg(xu))
168     { b = true;  return I(checking::neg_inf(), rnd.div_up(xu, yu), true); }
169   else if (::boost::numeric::interval_lib::user::is_neg(xl))
170     { b = false; return I(checking::neg_inf(), checking::pos_inf(), true); }
171   else
172     { b = true;  return I(checking::neg_inf(), rnd.div_up(xl, yl), true); }
173 }
174 
175 template<class T, class Policies> inline
div_zero_part2(const interval<T,Policies> & x,const interval<T,Policies> & y)176 interval<T, Policies> div_zero_part2(const interval<T, Policies>& x,
177                                      const interval<T, Policies>& y)
178 {
179   // assert(::boost::numeric::interval_lib::user::is_neg(y.lower()) && ::boost::numeric::interval_lib::user::is_pos(y.upper()) && (div_zero_part1(x, y, b), b));
180   typename Policies::rounding rnd;
181   typedef interval<T, Policies> I;
182   typedef typename Policies::checking checking;
183   if (::boost::numeric::interval_lib::user::is_neg(x.upper()))
184     return I(rnd.div_down(x.upper(), y.lower()), checking::pos_inf(), true);
185   else
186     return I(rnd.div_down(x.lower(), y.upper()), checking::pos_inf(), true);
187 }
188 
189 } // namespace detail
190 } // namespace interval_lib
191 } // namespace numeric
192 } // namespace boost
193 
194 #endif // BOOST_NUMERIC_INTERVAL_DETAIL_DIVISION_HPP
195