• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_NUMERIC_INTERVAL_HPP
2 #define BOOST_NUMERIC_INTERVAL_HPP
3 
4 //  Copyright (c) 2012 Robert Ramey
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 
10 #include <limits>
11 #include <cassert>
12 #include <type_traits>
13 #include <initializer_list>
14 #include <algorithm> // minmax, min, max
15 
16 #include <boost/logic/tribool.hpp>
17 
18 #include "utility.hpp" // log
19 
20 // from stack overflow
21 // http://stackoverflow.com/questions/23815138/implementing-variadic-min-max-functions
22 
23 namespace boost {
24 namespace safe_numerics {
25 
26 template<typename R>
27 struct interval {
28     const R l;
29     const R u;
30 
31     template<typename T>
intervalboost::safe_numerics::interval32     constexpr interval(const T & lower, const T & upper) :
33         l(lower),
34         u(upper)
35     {
36         // assert(static_cast<bool>(l <= u));
37     }
38     template<typename T>
intervalboost::safe_numerics::interval39     constexpr interval(const std::pair<T, T> & p) :
40         l(p.first),
41         u(p.second)
42     {}
43     template<class T>
intervalboost::safe_numerics::interval44     constexpr interval(const interval<T> & rhs) :
45         l(rhs.l),
46         u(rhs.u)
47     {}
48 
49     constexpr interval();
50 
51     // return true if this interval contains the given point
includesboost::safe_numerics::interval52     constexpr tribool includes(const R & t) const {
53         return l <= t && t <= u;
54     }
55     // if this interval contains every point found in some other inteval t
56     //  return true
57     // otherwise
58     //  return false or indeterminate
includesboost::safe_numerics::interval59     constexpr tribool includes(const interval<R> & t) const {
60         return u >= t.u && l <= t.l;
61     }
62 
63     // return true if this interval contains the given point
excludesboost::safe_numerics::interval64     constexpr tribool excludes(const R & t) const {
65         return t < l || t > u;
66     }
67     // if this interval excludes every point found in some other inteval t
68     //  return true
69     // otherwise
70     //  return false or indeterminate
excludesboost::safe_numerics::interval71     constexpr tribool excludes(const interval<R> & t) const {
72         return t.u < l || u < t.l;
73     }
74 
75 };
76 
77 template<class R>
make_interval()78 constexpr interval<R> make_interval(){
79     return interval<R>();
80 }
81 template<class R>
make_interval(const R & r)82 constexpr interval<R> make_interval(const R & r){
83     return interval<R>(r, r);
84 }
85 template<class R>
interval()86 constexpr interval<R>::interval() :
87     l(std::numeric_limits<R>::lowest()),
88     u(std::numeric_limits<R>::max())
89 {}
90 // account for the fact that for floats and doubles
91 // the most negative value is called "lowest" rather
92 // than min
93 template<>
interval()94 constexpr interval<float>::interval() :
95     l(std::numeric_limits<float>::lowest()),
96     u(std::numeric_limits<float>::max())
97 {}
98 template<>
interval()99 constexpr interval<double>::interval() :
100     l(std::numeric_limits<double>::lowest()),
101     u(std::numeric_limits<double>::max())
102 {}
103 
104 template<typename T>
operator +(const interval<T> & t,const interval<T> & u)105 constexpr interval<T> operator+(const interval<T> & t, const interval<T> & u){
106     // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
107     return {t.l + u.l, t.u + u.u};
108 }
109 
110 template<typename T>
operator -(const interval<T> & t,const interval<T> & u)111 constexpr interval<T> operator-(const interval<T> & t, const interval<T> & u){
112     // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
113     return {t.l - u.u, t.u - u.l};
114 }
115 
116 template<typename T>
operator *(const interval<T> & t,const interval<T> & u)117 constexpr interval<T> operator*(const interval<T> & t, const interval<T> & u){
118     // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
119     return utility::minmax<T>(
120         std::initializer_list<T> {
121             t.l * u.l,
122             t.l * u.u,
123             t.u * u.l,
124             t.u * u.u
125         }
126     );
127 }
128 
129 // interval division
130 // note: presumes 0 is not included in the range of the denominator
131 template<typename T>
operator /(const interval<T> & t,const interval<T> & u)132 constexpr interval<T> operator/(const interval<T> & t, const interval<T> & u){
133     assert(static_cast<bool>(u.excludes(T(0))));
134     return utility::minmax<T>(
135         std::initializer_list<T> {
136             t.l / u.l,
137             t.l / u.u,
138             t.u / u.l,
139             t.u / u.u
140         }
141     );
142 }
143 
144 // modulus of two intervals.  This will give a new range of for the modulus.
145 // note: presumes 0 is not included in the range of the denominator
146 template<typename T>
operator %(const interval<T> & t,const interval<T> & u)147 constexpr interval<T> operator%(const interval<T> & t, const interval<T> & u){
148     assert(static_cast<bool>(u.excludes(T(0))));
149     return utility::minmax<T>(
150         std::initializer_list<T> {
151             t.l % u.l,
152             t.l % u.u,
153             t.u % u.l,
154             t.u % u.u
155         }
156     );
157 }
158 
159 template<typename T>
operator <<(const interval<T> & t,const interval<T> & u)160 constexpr interval<T> operator<<(const interval<T> & t, const interval<T> & u){
161 //    static_assert(std::is_integral<T>::value, "left shift only defined for integral type");
162     //return interval<T>{t.l << u.l, t.u << u.u};
163     return utility::minmax<T>(
164         std::initializer_list<T> {
165             t.l << u.l,
166             t.l << u.u,
167             t.u << u.l,
168             t.u << u.u
169         }
170     );
171 }
172 
173 template<typename T>
operator >>(const interval<T> & t,const interval<T> & u)174 constexpr interval<T> operator>>(const interval<T> & t, const interval<T> & u){
175 //    static_assert(std::is_integral<T>::value, "right shift only defined for integral type");
176     //return interval<T>{t.l >> u.u, t.u >> u.l};
177     return utility::minmax<T>(
178         std::initializer_list<T> {
179             t.l >> u.l,
180             t.l >> u.u,
181             t.u >> u.l,
182             t.u >> u.u
183         }
184     );
185 }
186 
187 // union of two intervals
188 template<typename T>
operator |(const interval<T> & t,const interval<T> & u)189 constexpr interval<T> operator|(const interval<T> & t, const interval<T> & u){
190     const T & rl = std::min(t.l, u.l);
191     const T & ru = std::max(t.u, u.u);
192     return interval<T>(rl, ru);
193 }
194 
195 // intersection of two intervals
196 template<typename T>
operator &(const interval<T> & t,const interval<T> & u)197 constexpr interval<T> operator&(const interval<T> & t, const interval<T> & u){
198     const T & rl = std::max(t.l, u.l);
199     const T & ru = std::min(t.u, u.u);
200     return interval<T>(rl, ru);
201 }
202 
203 // determine whether two intervals intersect
204 template<typename T>
intersect(const interval<T> & t,const interval<T> & u)205 constexpr boost::logic::tribool intersect(const interval<T> & t, const interval<T> & u){
206     return t.u >= u.l || t.l <= u.u;
207 }
208 
209 template<typename T>
operator <(const interval<T> & t,const interval<T> & u)210 constexpr boost::logic::tribool operator<(
211     const interval<T> & t,
212     const interval<T> & u
213 ){
214     return
215         // if every element in t is less than every element in u
216         t.u < u.l ? boost::logic::tribool(true):
217         // if every element in t is greater than every element in u
218         t.l > u.u ? boost::logic::tribool(false):
219         // otherwise some element(s) in t are greater than some element in u
220         boost::logic::indeterminate
221     ;
222 }
223 
224 template<typename T>
operator >(const interval<T> & t,const interval<T> & u)225 constexpr boost::logic::tribool operator>(
226     const interval<T> & t,
227     const interval<T> & u
228 ){
229     return
230         // if every element in t is greater than every element in u
231         t.l > u.u ? boost::logic::tribool(true) :
232         // if every element in t is less than every element in u
233         t.u < u.l ? boost::logic::tribool(false) :
234         // otherwise some element(s) in t are greater than some element in u
235         boost::logic::indeterminate
236     ;
237 }
238 
239 template<typename T>
operator ==(const interval<T> & t,const interval<T> & u)240 constexpr bool operator==(
241     const interval<T> & t,
242     const interval<T> & u
243 ){
244     // intervals have the same limits
245     return t.l == u.l && t.u == u.u;
246 }
247 
248 template<typename T>
operator !=(const interval<T> & t,const interval<T> & u)249 constexpr bool operator!=(
250     const interval<T> & t,
251     const interval<T> & u
252 ){
253     return ! (t == u);
254 }
255 
256 template<typename T>
operator <=(const interval<T> & t,const interval<T> & u)257 constexpr boost::logic::tribool operator<=(
258     const interval<T> & t,
259     const interval<T> & u
260 ){
261     return ! (t > u);
262 }
263 
264 template<typename T>
operator >=(const interval<T> & t,const interval<T> & u)265 constexpr boost::logic::tribool operator>=(
266     const interval<T> & t,
267     const interval<T> & u
268 ){
269     return ! (t < u);
270 }
271 
272 } // safe_numerics
273 } // boost
274 
275 #include <iosfwd>
276 
277 namespace std {
278 
279 template<typename CharT, typename Traits, typename T>
280 inline std::basic_ostream<CharT, Traits> &
operator <<(std::basic_ostream<CharT,Traits> & os,const boost::safe_numerics::interval<T> & i)281 operator<<(
282     std::basic_ostream<CharT, Traits> & os,
283     const boost::safe_numerics::interval<T> & i
284 ){
285     return os << '[' << i.l << ',' << i.u << ']';
286 }
287 template<typename CharT, typename Traits>
288 inline std::basic_ostream<CharT, Traits> &
operator <<(std::basic_ostream<CharT,Traits> & os,const boost::safe_numerics::interval<unsigned char> & i)289 operator<<(
290     std::basic_ostream<CharT, Traits> & os,
291     const boost::safe_numerics::interval<unsigned char> & i
292 ){
293     os << "[" << (unsigned)i.l << "," << (unsigned)i.u << "]";
294     return os;
295 }
296 
297 template<typename CharT, typename Traits>
298 inline std::basic_ostream<CharT, Traits> &
operator <<(std::basic_ostream<CharT,Traits> & os,const boost::safe_numerics::interval<signed char> & i)299 operator<<(
300     std::basic_ostream<CharT, Traits> & os,
301     const boost::safe_numerics::interval<signed char> & i
302 ){
303     os << "[" << (int)i.l << "," << (int)i.u << "]";
304     return os;
305 }
306 
307 } // std
308 
309 
310 #endif // BOOST_NUMERIC_INTERVAL_HPP
311