interval.hpp 8.2 KB

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