ext-boost/boost/safe_numerics/interval.hpp
2019-12-14 02:33:01 -05:00

311 lines
8.2 KiB
C++

#ifndef BOOST_NUMERIC_INTERVAL_HPP
#define BOOST_NUMERIC_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 <limits>
#include <cassert>
#include <type_traits>
#include <initializer_list>
#include <algorithm> // minmax, min, max
#include <boost/logic/tribool.hpp>
#include "utility.hpp" // log
// from stack overflow
// http://stackoverflow.com/questions/23815138/implementing-variadic-min-max-functions
namespace boost {
namespace safe_numerics {
template<typename R>
struct interval {
const R l;
const R u;
template<typename T>
constexpr interval(const T & lower, const T & upper) :
l(lower),
u(upper)
{
// assert(static_cast<bool>(l <= u));
}
template<typename T>
constexpr interval(const std::pair<T, T> & p) :
l(p.first),
u(p.second)
{}
template<class T>
constexpr interval(const interval<T> & rhs) :
l(rhs.l),
u(rhs.u)
{}
constexpr interval();
// 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<R> & 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<R> & t) const {
return t.u < l || u < t.l;
}
};
template<class R>
constexpr interval<R> make_interval(){
return interval<R>();
}
template<class R>
constexpr interval<R> make_interval(const R & r){
return interval<R>(r, r);
}
template<class R>
constexpr interval<R>::interval() :
l(std::numeric_limits<R>::lowest()),
u(std::numeric_limits<R>::max())
{}
// account for the fact that for floats and doubles
// the most negative value is called "lowest" rather
// than min
template<>
constexpr interval<float>::interval() :
l(std::numeric_limits<float>::lowest()),
u(std::numeric_limits<float>::max())
{}
template<>
constexpr interval<double>::interval() :
l(std::numeric_limits<double>::lowest()),
u(std::numeric_limits<double>::max())
{}
template<typename T>
constexpr interval<T> operator+(const interval<T> & t, const interval<T> & u){
// adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
return {t.l + u.l, t.u + u.u};
}
template<typename T>
constexpr interval<T> operator-(const interval<T> & t, const interval<T> & u){
// adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
return {t.l - u.u, t.u - u.l};
}
template<typename T>
constexpr interval<T> operator*(const interval<T> & t, const interval<T> & u){
// adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
return utility::minmax<T>(
std::initializer_list<T> {
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<typename T>
constexpr interval<T> operator/(const interval<T> & t, const interval<T> & u){
assert(static_cast<bool>(u.excludes(T(0))));
return utility::minmax<T>(
std::initializer_list<T> {
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<typename T>
constexpr interval<T> operator%(const interval<T> & t, const interval<T> & u){
assert(static_cast<bool>(u.excludes(T(0))));
return utility::minmax<T>(
std::initializer_list<T> {
t.l % u.l,
t.l % u.u,
t.u % u.l,
t.u % u.u
}
);
}
template<typename T>
constexpr interval<T> operator<<(const interval<T> & t, const interval<T> & u){
// static_assert(std::is_integral<T>::value, "left shift only defined for integral type");
//return interval<T>{t.l << u.l, t.u << u.u};
return utility::minmax<T>(
std::initializer_list<T> {
t.l << u.l,
t.l << u.u,
t.u << u.l,
t.u << u.u
}
);
}
template<typename T>
constexpr interval<T> operator>>(const interval<T> & t, const interval<T> & u){
// static_assert(std::is_integral<T>::value, "right shift only defined for integral type");
//return interval<T>{t.l >> u.u, t.u >> u.l};
return utility::minmax<T>(
std::initializer_list<T> {
t.l >> u.l,
t.l >> u.u,
t.u >> u.l,
t.u >> u.u
}
);
}
// union of two intervals
template<typename T>
constexpr interval<T> operator|(const interval<T> & t, const interval<T> & u){
const T & rl = std::min(t.l, u.l);
const T & ru = std::max(t.u, u.u);
return interval<T>(rl, ru);
}
// intersection of two intervals
template<typename T>
constexpr interval<T> operator&(const interval<T> & t, const interval<T> & u){
const T & rl = std::max(t.l, u.l);
const T & ru = std::min(t.u, u.u);
return interval<T>(rl, ru);
}
// determine whether two intervals intersect
template<typename T>
constexpr boost::logic::tribool intersect(const interval<T> & t, const interval<T> & u){
return t.u >= u.l || t.l <= u.u;
}
template<typename T>
constexpr boost::logic::tribool operator<(
const interval<T> & t,
const interval<T> & 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<typename T>
constexpr boost::logic::tribool operator>(
const interval<T> & t,
const interval<T> & 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<typename T>
constexpr bool operator==(
const interval<T> & t,
const interval<T> & u
){
// intervals have the same limits
return t.l == u.l && t.u == u.u;
}
template<typename T>
constexpr bool operator!=(
const interval<T> & t,
const interval<T> & u
){
return ! (t == u);
}
template<typename T>
constexpr boost::logic::tribool operator<=(
const interval<T> & t,
const interval<T> & u
){
return ! (t > u);
}
template<typename T>
constexpr boost::logic::tribool operator>=(
const interval<T> & t,
const interval<T> & u
){
return ! (t < u);
}
} // safe_numerics
} // boost
#include <iosfwd>
namespace std {
template<typename CharT, typename Traits, typename T>
inline std::basic_ostream<CharT, Traits> &
operator<<(
std::basic_ostream<CharT, Traits> & os,
const boost::safe_numerics::interval<T> & i
){
return os << '[' << i.l << ',' << i.u << ']';
}
template<typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits> &
operator<<(
std::basic_ostream<CharT, Traits> & os,
const boost::safe_numerics::interval<unsigned char> & i
){
os << "[" << (unsigned)i.l << "," << (unsigned)i.u << "]";
return os;
}
template<typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits> &
operator<<(
std::basic_ostream<CharT, Traits> & os,
const boost::safe_numerics::interval<signed char> & i
){
os << "[" << (int)i.l << "," << (int)i.u << "]";
return os;
}
} // std
#endif // BOOST_NUMERIC_INTERVAL_HPP