#ifndef BOOST_SAFE_NUMERICS_INTERVAL_HPP #define BOOST_SAFE_NUMERICS_INTERVAL_HPP // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include // minmax, min, max #include #include "utility.hpp" // log #include "concept/integer.hpp" // from stack overflow // http://stackoverflow.com/questions/23815138/implementing-variadic-min-max-functions namespace boost { namespace safe_numerics { template struct interval { const R l; const R u; template constexpr interval(const T & lower, const T & upper) : l(lower), u(upper) { // assert(static_cast(l <= u)); } template constexpr interval(const std::pair & p) : l(p.first), u(p.second) {} template constexpr interval(const interval & rhs) : l(rhs.l), u(rhs.u) {} constexpr interval() : l(std::numeric_limits::min()), u(std::numeric_limits::max()) {} // return true if this interval contains the given point constexpr tribool includes(const R & t) const { return l <= t && t <= u; } // if this interval contains every point found in some other inteval t // return true // otherwise // return false or indeterminate constexpr tribool includes(const interval & t) const { return u >= t.u && l <= t.l; } // return true if this interval contains the given point constexpr tribool excludes(const R & t) const { return t < l || t > u; } // if this interval excludes every point found in some other inteval t // return true // otherwise // return false or indeterminate constexpr tribool excludes(const interval & t) const { return t.u < l || u < t.l; } }; template constexpr inline interval make_interval(){ return interval(); } template constexpr inline interval make_interval(const R &){ return interval(); } // account for the fact that for floats and doubles // the most negative value is called "lowest" rather // than min template<> constexpr inline interval::interval() : l(std::numeric_limits::lowest()), u(std::numeric_limits::max()) {} template<> constexpr inline interval::interval() : l(std::numeric_limits::lowest()), u(std::numeric_limits::max()) {} template constexpr inline interval operator+(const interval & t, const interval & u){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic return {t.l + u.l, t.u + u.u}; } template constexpr inline interval operator-(const interval & t, const interval & u){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic return {t.l - u.u, t.u - u.l}; } template constexpr inline interval operator*(const interval & t, const interval & u){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic return utility::minmax( std::initializer_list { t.l * u.l, t.l * u.u, t.u * u.l, t.u * u.u } ); } // interval division // note: presumes 0 is not included in the range of the denominator template constexpr inline interval operator/(const interval & t, const interval & u){ assert(static_cast(u.excludes(T(0)))); return utility::minmax( std::initializer_list { t.l / u.l, t.l / u.u, t.u / u.l, t.u / u.u } ); } // modulus of two intervals. This will give a new range of for the modulus. // note: presumes 0 is not included in the range of the denominator template constexpr inline interval operator%(const interval & t, const interval & u){ assert(static_cast(u.excludes(T(0)))); return utility::minmax( std::initializer_list { t.l % u.l, t.l % u.u, t.u % u.l, t.u % u.u } ); } template constexpr inline interval operator<<(const interval & t, const interval & u){ static_assert( boost::safe_numerics::Integer::value, "left shift only defined for integral type" ); //return interval{t.l << u.l, t.u << u.u}; return utility::minmax( std::initializer_list { t.l << u.l, t.l << u.u, t.u << u.l, t.u << u.u } ); } template constexpr inline interval operator>>(const interval & t, const interval & u){ static_assert( boost::safe_numerics::Integer::value, "right shift only defined for integral type" ); //return interval{t.l >> u.u, t.u >> u.l}; return utility::minmax( std::initializer_list { t.l >> u.l, t.l >> u.u, t.u >> u.l, t.u >> u.u } ); } // union of two intervals template constexpr interval operator|(const interval & t, const interval & u){ const T & rl = std::min(t.l, u.l); const T & ru = std::max(t.u, u.u); return interval(rl, ru); } // intersection of two intervals template constexpr inline interval operator&(const interval & t, const interval & u){ const T & rl = std::max(t.l, u.l); const T & ru = std::min(t.u, u.u); return interval(rl, ru); } // determine whether two intervals intersect template constexpr inline boost::logic::tribool intersect(const interval & t, const interval & u){ return t.u >= u.l || t.l <= u.u; } template constexpr inline boost::logic::tribool operator<( const interval & t, const interval & u ){ return // if every element in t is less than every element in u t.u < u.l ? boost::logic::tribool(true): // if every element in t is greater than every element in u t.l > u.u ? boost::logic::tribool(false): // otherwise some element(s) in t are greater than some element in u boost::logic::indeterminate ; } template constexpr inline boost::logic::tribool operator>( const interval & t, const interval & u ){ return // if every element in t is greater than every element in u t.l > u.u ? boost::logic::tribool(true) : // if every element in t is less than every element in u t.u < u.l ? boost::logic::tribool(false) : // otherwise some element(s) in t are greater than some element in u boost::logic::indeterminate ; } template constexpr inline bool operator==( const interval & t, const interval & u ){ // intervals have the same limits return t.l == u.l && t.u == u.u; } template constexpr inline bool operator!=( const interval & t, const interval & u ){ return ! (t == u); } template constexpr inline boost::logic::tribool operator<=( const interval & t, const interval & u ){ return ! (t > u); } template constexpr inline boost::logic::tribool operator>=( const interval & t, const interval & u ){ return ! (t < u); } } // safe_numerics } // boost #include namespace std { template inline std::basic_ostream & operator<<( std::basic_ostream & os, const boost::safe_numerics::interval & i ){ return os << '[' << i.l << ',' << i.u << ']'; } template inline std::basic_ostream & operator<<( std::basic_ostream & os, const boost::safe_numerics::interval & i ){ os << "[" << (unsigned)i.l << "," << (unsigned)i.u << "]"; return os; } template inline std::basic_ostream & operator<<( std::basic_ostream & os, const boost::safe_numerics::interval & i ){ os << "[" << (int)i.l << "," << (int)i.u << "]"; return os; } } // std #endif // BOOST_SAFE_NUMERICS_INTERVAL_HPP