interval.hpp 8.4 KB

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