#ifndef BOOST_NUMERIC_INTERVAL_HPP #define BOOST_NUMERIC_INTERVAL_HPP // MS compatible compilers support #pragma once #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif // 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 // quick_exit #include #include #include #include #include "utility.hpp" // log #include "checked_result.hpp" #include "checked.hpp" // from stack overflow // http://stackoverflow.com/questions/23815138/implementing-variadic-min-max-functions namespace boost { namespace numeric { template struct interval { static_assert( std::is_literal_type< checked_result >::value, "is literal type" ); const R l; const R u; template constexpr interval(const T & lower, const T & upper) : l(lower), u(upper) {} 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 every point found in some // other inteval t template constexpr bool includes(const interval & t) const { return safe_compare::greater_than_equal(t.l, l) && safe_compare::less_than_equal(t.u, u) ; } template constexpr bool includes(const T & t) const { return safe_compare::greater_than_equal(t, l) && safe_compare::less_than_equal(t, u) ; } }; namespace { template constexpr checked_result> failed_result( exception_type::domain_error, "indefinite interval" ); // create constexpr versions of stl algorthms which are not (yet) // constexpr. template constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q) { for (; first != last; ++first) { if (!q(*first)) { return first; } } return last; } template constexpr InputIt find(InputIt first, InputIt last, const T& value) { for (; first != last; ++first) { if (*first == value) { return first; } } return last; } template constexpr bool less_than( const checked_result & lhs, const checked_result & rhs ){ return (lhs.no_exception() && rhs.no_exception()) ? safe_compare::less_than(lhs.m_r, rhs.m_r) : false ; } template constexpr checked_result> select( const std::initializer_list> & acr ){ typename std::initializer_list>::const_iterator const e = find_if_not( acr.begin(), acr.end(), no_exception ); return (acr.end() == e) ? checked_result>( interval(std::minmax(acr, less_than)) ) : failed_result// throw assert_failure([]{assert(!"input not in range");}) ; } } // namespace template constexpr checked_result> add( const interval & t, const interval & u ){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic checked_result lower = checked::add(static_cast(t.l), static_cast(u.l)); if(! lower.no_exception()) return failed_result; checked_result upper = checked::add(static_cast(t.u), static_cast(u.u)); if(! upper.no_exception()) return failed_result; return interval(lower, upper); } template constexpr checked_result> subtract(const interval & t, const interval & u){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic checked_result lower = checked::subtract(static_cast(t.l), static_cast(u.u)); if(! lower.no_exception()) return failed_result; checked_result upper = checked::subtract(static_cast(t.u), static_cast(u.l)); if(! upper.no_exception()) return failed_result; return interval(lower, upper); } template constexpr checked_result> multiply(const interval & t, const interval & u){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic return select( std::initializer_list> { checked::multiply(t.l, u.l), checked::multiply(t.l, u.u), checked::multiply(t.u, u.l), checked::multiply(t.u, u.u) } ); } // divide two intervals. BUT don't consider the possibility that the // denominator might contain a zero. template constexpr inline checked_result> divide_nz( const interval & t, const interval & u ){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic return select( (u.u < 0 || u.l > 0) ? std::initializer_list> { checked::divide(t.l, u.l), checked::divide(t.l, u.u), checked::divide(t.u, u.l), checked::divide(t.u, u.u) } : std::initializer_list> { checked::divide(t.l, u.l), checked::divide(t.l, -1), checked::divide(t.u, u.l), checked::divide(t.u, -1), checked::divide(t.l, 1), checked::divide(t.l, u.u), checked::divide(t.u, 1), checked::divide(t.u, u.u) } ); } template constexpr inline checked_result> divide( const interval & t, const interval & u ){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic if(u.l <= 0 && u.u >= 0) return checked_result>( exception_type::domain_error, "interval divisor includes zero" ); return divide_nz(t, u); } template constexpr checked_result> modulus_nz( const interval & t, const interval & u ){ return select( (u.u < 0 || u.l > 0) ? std::initializer_list> { checked::modulus(t.l, u.l), checked::modulus(t.l, u.u), checked::modulus(t.u, u.l), checked::modulus(t.u, u.u) } : std::initializer_list> { checked::modulus(t.l, u.l), checked::modulus(t.l, -1), checked::modulus(t.u, u.l), checked::modulus(t.u, 1), checked::modulus(t.l, 1), checked::modulus(t.l, u.u), checked::modulus(t.u, 1), checked::modulus(t.u, u.u) } ); } template constexpr checked_result> modulus( const interval & t, const interval & u ){ // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic if(u.l <= 0 && u.u >= 0) return checked_result>( exception_type::domain_error, "interval modulus includes zero" ); return modulus_nz(t, u); } template constexpr checked_result> left_shift( const interval & t, const interval & u ){ return select( std::initializer_list> { checked::left_shift(t.l, u.l), checked::left_shift(t.l, u.u), checked::left_shift(t.u, u.l), checked::left_shift(t.u, u.u) }); } template constexpr checked_result> right_shift( const interval & t, const interval & u ){ return select( std::initializer_list> { checked::right_shift(t.l, u.l), checked::right_shift(t.l, u.u), checked::right_shift(t.u, u.l), checked::right_shift(t.u, u.u) }); } template constexpr checked_result> right_shift_positive( const interval & t, const interval & u ){ const U ul = safe_compare::greater_than(0, u.l) ? 0 : u.l; const U ux = boost::numeric::log(std::numeric_limits::max()); const U uu = safe_compare::less_than(u.u, ux) ? u.u : ux; return select( std::initializer_list> { checked::right_shift(t.l, ul), checked::right_shift(t.l, uu), checked::right_shift(t.u, ul), checked::right_shift(t.u, uu) }); } template constexpr checked_result> intersection( const interval & t, const interval & u ){ const R rl = safe_compare::greater_than(t.l, u.l) ? t.l : u.l; const R ru = safe_compare::less_than(t, u) ? t.u : u.u; if(safe_compare::greater_than(rl, ru)){ return checked_result>( exception_type::uninitialized, "null intersection" ); } return interval(rl, ru); } template constexpr checked_result> union_interval( const interval & t, const interval & u ){ const R rl = safe_compare::less_than(t.l, u.l) ? t.l : u.l; const R ru = safe_compare::greater_than(t, u) ? t.u : u.u; if(safe_compare::greater_than(rl, ru)){ return checked_result>( exception_type::uninitialized, "null intersection" ); } return interval(rl, ru); } template constexpr boost::logic::tribool operator<( const interval & t, const interval & u ){ return // if every element in t is less than every element in u safe_compare::less_than(t.u, u.l) ? boost::logic::tribool(true) : // if every element in t is greater than every element in u safe_compare::greater_than(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 boost::logic::tribool operator>( const interval & t, const interval & u ){ return // if every element in t is greater than every element in u safe_compare::greater_than(t.l, u.u) ? boost::logic::tribool(true) : // if every element in t is less than every element in u safe_compare::less_than(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 bool operator==( const interval & t, const interval & u ){ // intervals have the same limits return safe_compare::equal(t.l, u.l) && safe_compare::equal(t.u, u.u) ; } template constexpr bool operator!=( const interval & t, const interval & u ){ return ! (t == u); } template constexpr boost::logic::tribool operator<=( const interval & t, const interval & u ){ return ! (t > u); } template constexpr boost::logic::tribool operator>=( const interval & t, const interval & u ){ return ! (t < u); } } // numeric } // boost #include namespace std { template std::ostream & operator<<(std::ostream & os, const boost::numeric::interval & i){ os << "[" << i.l << "," << i.u << "]"; return os; } template<> std::ostream & operator<<(std::ostream & os, const boost::numeric::interval & i){ os << "[" << (unsigned)i.l << "," << (unsigned)i.u << "]"; return os; } template<> std::ostream & operator<<(std::ostream & os, const boost::numeric::interval & i){ os << "[" << (int)i.l << "," << (int)i.u << "]"; return os; } } // std #endif // BOOST_NUMERIC_INTERVAL_HPP