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