306 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
/* Boost interval/arith.hpp template implementation file
 | 
						|
 *
 | 
						|
 * Copyright 2000 Jens Maurer
 | 
						|
 * Copyright 2002-2003 Hervé Brönnimann, Guillaume Melquiond, Sylvain Pion
 | 
						|
 *
 | 
						|
 * 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)
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef BOOST_NUMERIC_INTERVAL_ARITH_HPP
 | 
						|
#define BOOST_NUMERIC_INTERVAL_ARITH_HPP
 | 
						|
 | 
						|
#include <boost/config.hpp>
 | 
						|
#include <boost/numeric/interval/interval.hpp>
 | 
						|
#include <boost/numeric/interval/detail/bugs.hpp>
 | 
						|
#include <boost/numeric/interval/detail/test_input.hpp>
 | 
						|
#include <boost/numeric/interval/detail/division.hpp>
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
namespace boost {
 | 
						|
namespace numeric {
 | 
						|
 | 
						|
/*
 | 
						|
 * Basic arithmetic operators
 | 
						|
 */
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
const interval<T, Policies>& operator+(const interval<T, Policies>& x)
 | 
						|
{
 | 
						|
  return x;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator-(const interval<T, Policies>& x)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  return interval<T, Policies>(-x.upper(), -x.lower(), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator+=(const interval<T, Policies>& r)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(*this, r))
 | 
						|
    set_empty();
 | 
						|
  else {
 | 
						|
    typename Policies::rounding rnd;
 | 
						|
    set(rnd.add_down(low, r.low), rnd.add_up(up, r.up));
 | 
						|
  }
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator+=(const T& r)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(*this, r))
 | 
						|
    set_empty();
 | 
						|
  else {
 | 
						|
    typename Policies::rounding rnd;
 | 
						|
    set(rnd.add_down(low, r), rnd.add_up(up, r));
 | 
						|
  }
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator-=(const interval<T, Policies>& r)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(*this, r))
 | 
						|
    set_empty();
 | 
						|
  else {
 | 
						|
    typename Policies::rounding rnd;
 | 
						|
    set(rnd.sub_down(low, r.up), rnd.sub_up(up, r.low));
 | 
						|
  }
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator-=(const T& r)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(*this, r))
 | 
						|
    set_empty();
 | 
						|
  else {
 | 
						|
    typename Policies::rounding rnd;
 | 
						|
    set(rnd.sub_down(low, r), rnd.sub_up(up, r));
 | 
						|
  }
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator*=(const interval<T, Policies>& r)
 | 
						|
{
 | 
						|
  return *this = *this * r;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator*=(const T& r)
 | 
						|
{
 | 
						|
  return *this = r * *this;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator/=(const interval<T, Policies>& r)
 | 
						|
{
 | 
						|
  return *this = *this / r;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies>& interval<T, Policies>::operator/=(const T& r)
 | 
						|
{
 | 
						|
  return *this = *this / r;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator+(const interval<T, Policies>& x,
 | 
						|
                                const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  return interval<T,Policies>(rnd.add_down(x.lower(), y.lower()),
 | 
						|
                              rnd.add_up  (x.upper(), y.upper()), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator+(const T& x, const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  return interval<T,Policies>(rnd.add_down(x, y.lower()),
 | 
						|
                              rnd.add_up  (x, y.upper()), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator+(const interval<T, Policies>& x, const T& y)
 | 
						|
{ return y + x; }
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator-(const interval<T, Policies>& x,
 | 
						|
                                const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  return interval<T,Policies>(rnd.sub_down(x.lower(), y.upper()),
 | 
						|
                              rnd.sub_up  (x.upper(), y.lower()), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator-(const T& x, const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  return interval<T,Policies>(rnd.sub_down(x, y.upper()),
 | 
						|
                              rnd.sub_up  (x, y.lower()), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator-(const interval<T, Policies>& x, const T& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  return interval<T,Policies>(rnd.sub_down(x.lower(), y),
 | 
						|
                              rnd.sub_up  (x.upper(), y), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator*(const interval<T, Policies>& x,
 | 
						|
                                const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  BOOST_USING_STD_MIN();
 | 
						|
  BOOST_USING_STD_MAX();
 | 
						|
  typedef interval<T, Policies> I;
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return I::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  const T& xl = x.lower();
 | 
						|
  const T& xu = x.upper();
 | 
						|
  const T& yl = y.lower();
 | 
						|
  const T& yu = y.upper();
 | 
						|
 | 
						|
  if (interval_lib::user::is_neg(xl))
 | 
						|
    if (interval_lib::user::is_pos(xu))
 | 
						|
      if (interval_lib::user::is_neg(yl))
 | 
						|
        if (interval_lib::user::is_pos(yu)) // M * M
 | 
						|
          return I(min BOOST_PREVENT_MACRO_SUBSTITUTION(rnd.mul_down(xl, yu), rnd.mul_down(xu, yl)),
 | 
						|
                   max BOOST_PREVENT_MACRO_SUBSTITUTION(rnd.mul_up  (xl, yl), rnd.mul_up  (xu, yu)), true);
 | 
						|
        else                    // M * N
 | 
						|
          return I(rnd.mul_down(xu, yl), rnd.mul_up(xl, yl), true);
 | 
						|
      else
 | 
						|
        if (interval_lib::user::is_pos(yu)) // M * P
 | 
						|
          return I(rnd.mul_down(xl, yu), rnd.mul_up(xu, yu), true);
 | 
						|
        else                    // M * Z
 | 
						|
          return I(static_cast<T>(0), static_cast<T>(0), true);
 | 
						|
    else
 | 
						|
      if (interval_lib::user::is_neg(yl))
 | 
						|
        if (interval_lib::user::is_pos(yu)) // N * M
 | 
						|
          return I(rnd.mul_down(xl, yu), rnd.mul_up(xl, yl), true);
 | 
						|
        else                    // N * N
 | 
						|
          return I(rnd.mul_down(xu, yu), rnd.mul_up(xl, yl), true);
 | 
						|
      else
 | 
						|
        if (interval_lib::user::is_pos(yu)) // N * P
 | 
						|
          return I(rnd.mul_down(xl, yu), rnd.mul_up(xu, yl), true);
 | 
						|
        else                    // N * Z
 | 
						|
          return I(static_cast<T>(0), static_cast<T>(0), true);
 | 
						|
  else
 | 
						|
    if (interval_lib::user::is_pos(xu))
 | 
						|
      if (interval_lib::user::is_neg(yl))
 | 
						|
        if (interval_lib::user::is_pos(yu)) // P * M
 | 
						|
          return I(rnd.mul_down(xu, yl), rnd.mul_up(xu, yu), true);
 | 
						|
        else                    // P * N
 | 
						|
          return I(rnd.mul_down(xu, yl), rnd.mul_up(xl, yu), true);
 | 
						|
      else
 | 
						|
        if (interval_lib::user::is_pos(yu)) // P * P
 | 
						|
          return I(rnd.mul_down(xl, yl), rnd.mul_up(xu, yu), true);
 | 
						|
        else                    // P * Z
 | 
						|
          return I(static_cast<T>(0), static_cast<T>(0), true);
 | 
						|
    else                        // Z * ?
 | 
						|
      return I(static_cast<T>(0), static_cast<T>(0), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator*(const T& x, const interval<T, Policies>& y)
 | 
						|
{ 
 | 
						|
  typedef interval<T, Policies> I;
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return I::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  const T& yl = y.lower();
 | 
						|
  const T& yu = y.upper();
 | 
						|
  // x is supposed not to be infinite
 | 
						|
  if (interval_lib::user::is_neg(x))
 | 
						|
    return I(rnd.mul_down(x, yu), rnd.mul_up(x, yl), true);
 | 
						|
  else if (interval_lib::user::is_zero(x))
 | 
						|
    return I(static_cast<T>(0), static_cast<T>(0), true);
 | 
						|
  else
 | 
						|
    return I(rnd.mul_down(x, yl), rnd.mul_up(x, yu), true);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator*(const interval<T, Policies>& x, const T& y)
 | 
						|
{ return y * x; }
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator/(const interval<T, Policies>& x,
 | 
						|
                                const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  if (zero_in(y))
 | 
						|
    if (!interval_lib::user::is_zero(y.lower()))
 | 
						|
      if (!interval_lib::user::is_zero(y.upper()))
 | 
						|
        return interval_lib::detail::div_zero(x);
 | 
						|
      else
 | 
						|
        return interval_lib::detail::div_negative(x, y.lower());
 | 
						|
    else
 | 
						|
      if (!interval_lib::user::is_zero(y.upper()))
 | 
						|
        return interval_lib::detail::div_positive(x, y.upper());
 | 
						|
      else
 | 
						|
        return interval<T, Policies>::empty();
 | 
						|
  else
 | 
						|
    return interval_lib::detail::div_non_zero(x, y);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator/(const T& x, const interval<T, Policies>& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  if (zero_in(y))
 | 
						|
    if (!interval_lib::user::is_zero(y.lower()))
 | 
						|
      if (!interval_lib::user::is_zero(y.upper()))
 | 
						|
        return interval_lib::detail::div_zero<T, Policies>(x);
 | 
						|
      else
 | 
						|
        return interval_lib::detail::div_negative<T, Policies>(x, y.lower());
 | 
						|
    else
 | 
						|
      if (!interval_lib::user::is_zero(y.upper()))
 | 
						|
        return interval_lib::detail::div_positive<T, Policies>(x, y.upper());
 | 
						|
      else
 | 
						|
        return interval<T, Policies>::empty();
 | 
						|
  else
 | 
						|
    return interval_lib::detail::div_non_zero(x, y);
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class Policies> inline
 | 
						|
interval<T, Policies> operator/(const interval<T, Policies>& x, const T& y)
 | 
						|
{
 | 
						|
  if (interval_lib::detail::test_input(x, y) || interval_lib::user::is_zero(y))
 | 
						|
    return interval<T, Policies>::empty();
 | 
						|
  typename Policies::rounding rnd;
 | 
						|
  const T& xl = x.lower();
 | 
						|
  const T& xu = x.upper();
 | 
						|
  if (interval_lib::user::is_neg(y))
 | 
						|
    return interval<T, Policies>(rnd.div_down(xu, y), rnd.div_up(xl, y), true);
 | 
						|
  else
 | 
						|
    return interval<T, Policies>(rnd.div_down(xl, y), rnd.div_up(xu, y), true);
 | 
						|
}
 | 
						|
 | 
						|
} // namespace numeric
 | 
						|
} // namespace boost
 | 
						|
 | 
						|
#endif // BOOST_NUMERIC_INTERVAL_ARITH_HPP
 |