Chris@16: /* Boost interval/arith2.hpp template implementation file Chris@16: * Chris@16: * This header provides some auxiliary arithmetic Chris@16: * functions: fmod, sqrt, square, pov, inverse and Chris@16: * a multi-interval division. Chris@16: * Chris@16: * Copyright 2002-2003 Hervé Brönnimann, Guillaume Melquiond, Sylvain Pion Chris@16: * Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or Chris@16: * copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_NUMERIC_INTERVAL_ARITH2_HPP Chris@16: #define BOOST_NUMERIC_INTERVAL_ARITH2_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace numeric { Chris@16: Chris@16: template inline Chris@16: interval fmod(const interval& x, Chris@16: const interval& y) Chris@16: { Chris@16: if (interval_lib::detail::test_input(x, y)) Chris@16: return interval::empty(); Chris@16: typename Policies::rounding rnd; Chris@16: typedef typename interval_lib::unprotect >::type I; Chris@16: T const &yb = interval_lib::user::is_neg(x.lower()) ? y.lower() : y.upper(); Chris@16: T n = rnd.int_down(rnd.div_down(x.lower(), yb)); Chris@16: return (const I&)x - n * (const I&)y; Chris@16: } Chris@16: Chris@16: template inline Chris@16: interval fmod(const interval& x, const T& y) Chris@16: { Chris@16: if (interval_lib::detail::test_input(x, y)) Chris@16: return interval::empty(); Chris@16: typename Policies::rounding rnd; Chris@16: typedef typename interval_lib::unprotect >::type I; Chris@16: T n = rnd.int_down(rnd.div_down(x.lower(), y)); Chris@16: return (const I&)x - n * I(y); Chris@16: } Chris@16: Chris@16: template inline Chris@16: interval fmod(const T& x, const interval& y) Chris@16: { Chris@16: if (interval_lib::detail::test_input(x, y)) Chris@16: return interval::empty(); Chris@16: typename Policies::rounding rnd; Chris@16: typedef typename interval_lib::unprotect >::type I; Chris@16: T const &yb = interval_lib::user::is_neg(x) ? y.lower() : y.upper(); Chris@16: T n = rnd.int_down(rnd.div_down(x, yb)); Chris@16: return x - n * (const I&)y; Chris@16: } Chris@16: Chris@16: namespace interval_lib { Chris@16: Chris@16: template inline Chris@16: interval division_part1(const interval& x, Chris@16: const interval& y, bool& b) Chris@16: { Chris@16: typedef interval I; Chris@16: b = false; Chris@16: if (detail::test_input(x, y)) Chris@16: return I::empty(); Chris@16: if (zero_in(y)) Chris@16: if (!user::is_zero(y.lower())) Chris@16: if (!user::is_zero(y.upper())) Chris@16: return detail::div_zero_part1(x, y, b); Chris@16: else Chris@16: return detail::div_negative(x, y.lower()); Chris@16: else Chris@16: if (!user::is_zero(y.upper())) Chris@16: return detail::div_positive(x, y.upper()); Chris@16: else Chris@16: return I::empty(); Chris@16: else Chris@16: return detail::div_non_zero(x, y); Chris@16: } Chris@16: Chris@16: template inline Chris@16: interval division_part2(const interval& x, Chris@16: const interval& y, bool b = true) Chris@16: { Chris@16: if (!b) return interval::empty(); Chris@16: return detail::div_zero_part2(x, y); Chris@16: } Chris@16: Chris@16: template inline Chris@16: interval multiplicative_inverse(const interval& x) Chris@16: { Chris@16: typedef interval I; Chris@16: if (detail::test_input(x)) Chris@16: return I::empty(); Chris@16: T one = static_cast(1); Chris@16: typename Policies::rounding rnd; Chris@16: if (zero_in(x)) { Chris@16: typedef typename Policies::checking checking; Chris@16: if (!user::is_zero(x.lower())) Chris@16: if (!user::is_zero(x.upper())) Chris@16: return I::whole(); Chris@16: else Chris@16: return I(checking::neg_inf(), rnd.div_up(one, x.lower()), true); Chris@16: else Chris@16: if (!user::is_zero(x.upper())) Chris@16: return I(rnd.div_down(one, x.upper()), checking::pos_inf(), true); Chris@16: else Chris@16: return I::empty(); Chris@16: } else Chris@16: return I(rnd.div_down(one, x.upper()), rnd.div_up(one, x.lower()), true); Chris@16: } Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template inline Chris@16: T pow_dn(const T& x_, int pwr, Rounding& rnd) // x and pwr are positive Chris@16: { Chris@16: T x = x_; Chris@16: T y = (pwr & 1) ? x_ : static_cast(1); Chris@16: pwr >>= 1; Chris@16: while (pwr > 0) { Chris@16: x = rnd.mul_down(x, x); Chris@16: if (pwr & 1) y = rnd.mul_down(x, y); Chris@16: pwr >>= 1; Chris@16: } Chris@16: return y; Chris@16: } Chris@16: Chris@16: template inline Chris@16: T pow_up(const T& x_, int pwr, Rounding& rnd) // x and pwr are positive Chris@16: { Chris@16: T x = x_; Chris@16: T y = (pwr & 1) ? x_ : static_cast(1); Chris@16: pwr >>= 1; Chris@16: while (pwr > 0) { Chris@16: x = rnd.mul_up(x, x); Chris@16: if (pwr & 1) y = rnd.mul_up(x, y); Chris@16: pwr >>= 1; Chris@16: } Chris@16: return y; Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace interval_lib Chris@16: Chris@16: template inline Chris@16: interval pow(const interval& x, int pwr) Chris@16: { Chris@16: BOOST_USING_STD_MAX(); Chris@16: using interval_lib::detail::pow_dn; Chris@16: using interval_lib::detail::pow_up; Chris@16: typedef interval I; Chris@16: Chris@16: if (interval_lib::detail::test_input(x)) Chris@16: return I::empty(); Chris@16: Chris@16: if (pwr == 0) Chris@16: if (interval_lib::user::is_zero(x.lower()) Chris@16: && interval_lib::user::is_zero(x.upper())) Chris@16: return I::empty(); Chris@16: else Chris@16: return I(static_cast(1)); Chris@16: else if (pwr < 0) Chris@16: return interval_lib::multiplicative_inverse(pow(x, -pwr)); Chris@16: Chris@16: typename Policies::rounding rnd; Chris@16: Chris@16: if (interval_lib::user::is_neg(x.upper())) { // [-2,-1] Chris@16: T yl = pow_dn(static_cast(-x.upper()), pwr, rnd); Chris@16: T yu = pow_up(static_cast(-x.lower()), pwr, rnd); Chris@16: if (pwr & 1) // [-2,-1]^1 Chris@16: return I(-yu, -yl, true); Chris@16: else // [-2,-1]^2 Chris@16: return I(yl, yu, true); Chris@16: } else if (interval_lib::user::is_neg(x.lower())) { // [-1,1] Chris@16: if (pwr & 1) { // [-1,1]^1 Chris@16: return I(-pow_up(static_cast(-x.lower()), pwr, rnd), pow_up(x.upper(), pwr, rnd), true); Chris@16: } else { // [-1,1]^2 Chris@16: return I(static_cast(0), pow_up(max BOOST_PREVENT_MACRO_SUBSTITUTION(static_cast(-x.lower()), x.upper()), pwr, rnd), true); Chris@16: } Chris@16: } else { // [1,2] Chris@16: return I(pow_dn(x.lower(), pwr, rnd), pow_up(x.upper(), pwr, rnd), true); Chris@16: } Chris@16: } Chris@16: Chris@16: template inline Chris@16: interval sqrt(const interval& x) Chris@16: { Chris@16: typedef interval I; Chris@16: if (interval_lib::detail::test_input(x) || interval_lib::user::is_neg(x.upper())) Chris@16: return I::empty(); Chris@16: typename Policies::rounding rnd; Chris@16: T l = !interval_lib::user::is_pos(x.lower()) ? static_cast(0) : rnd.sqrt_down(x.lower()); Chris@16: return I(l, rnd.sqrt_up(x.upper()), true); Chris@16: } Chris@16: Chris@16: template inline Chris@16: interval square(const interval& x) Chris@16: { Chris@16: typedef interval I; Chris@16: if (interval_lib::detail::test_input(x)) Chris@16: return I::empty(); Chris@16: typename Policies::rounding rnd; Chris@16: const T& xl = x.lower(); Chris@16: const T& xu = x.upper(); Chris@16: if (interval_lib::user::is_neg(xu)) Chris@16: return I(rnd.mul_down(xu, xu), rnd.mul_up(xl, xl), true); Chris@16: else if (interval_lib::user::is_pos(x.lower())) Chris@16: return I(rnd.mul_down(xl, xl), rnd.mul_up(xu, xu), true); Chris@16: else Chris@16: return I(static_cast(0), (-xl > xu ? rnd.mul_up(xl, xl) : rnd.mul_up(xu, xu)), true); Chris@16: } Chris@16: Chris@16: namespace interval_lib { Chris@16: namespace detail { Chris@16: Chris@16: template< class I > inline Chris@16: I root_aux(typename I::base_type const &x, int k) // x and k are bigger than one Chris@16: { Chris@16: typedef typename I::base_type T; Chris@16: T tk(k); Chris@16: I y(static_cast(1), x, true); Chris@16: for(;;) { Chris@16: T y0 = median(y); Chris@16: I yy = intersect(y, y0 - (pow(I(y0, y0, true), k) - x) / (tk * pow(y, k - 1))); Chris@16: if (equal(y, yy)) return y; Chris@16: y = yy; Chris@16: } Chris@16: } Chris@16: Chris@16: template< class I > inline // x is positive and k bigger than one Chris@16: typename I::base_type root_aux_dn(typename I::base_type const &x, int k) Chris@16: { Chris@16: typedef typename I::base_type T; Chris@16: typedef typename I::traits_type Policies; Chris@16: typename Policies::rounding rnd; Chris@16: T one(1); Chris@16: if (x > one) return root_aux(x, k).lower(); Chris@16: if (x == one) return one; Chris@16: return rnd.div_down(one, root_aux(rnd.div_up(one, x), k).upper()); Chris@16: } Chris@16: Chris@16: template< class I > inline // x is positive and k bigger than one Chris@16: typename I::base_type root_aux_up(typename I::base_type const &x, int k) Chris@16: { Chris@16: typedef typename I::base_type T; Chris@16: typedef typename I::traits_type Policies; Chris@16: typename Policies::rounding rnd; Chris@16: T one(1); Chris@16: if (x > one) return root_aux(x, k).upper(); Chris@16: if (x == one) return one; Chris@16: return rnd.div_up(one, root_aux(rnd.div_down(one, x), k).lower()); Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace interval_lib Chris@16: Chris@16: template< class T, class Policies > inline Chris@16: interval nth_root(interval const &x, int k) Chris@16: { Chris@16: typedef interval I; Chris@16: if (interval_lib::detail::test_input(x)) return I::empty(); Chris@16: assert(k > 0); Chris@16: if (k == 1) return x; Chris@16: typename Policies::rounding rnd; Chris@16: typedef typename interval_lib::unprotect::type R; Chris@16: if (!interval_lib::user::is_pos(x.upper())) { Chris@16: if (interval_lib::user::is_zero(x.upper())) { Chris@16: T zero(0); Chris@16: if (!(k & 1) || interval_lib::user::is_zero(x.lower())) // [-1,0]^/2 or [0,0] Chris@16: return I(zero, zero, true); Chris@16: else // [-1,0]^/3 Chris@16: return I(-interval_lib::detail::root_aux_up(-x.lower(), k), zero, true); Chris@16: } else if (!(k & 1)) // [-2,-1]^/2 Chris@16: return I::empty(); Chris@16: else { // [-2,-1]^/3 Chris@16: return I(-interval_lib::detail::root_aux_up(-x.lower(), k), Chris@16: -interval_lib::detail::root_aux_dn(-x.upper(), k), true); Chris@16: } Chris@16: } Chris@16: T u = interval_lib::detail::root_aux_up(x.upper(), k); Chris@16: if (!interval_lib::user::is_pos(x.lower())) Chris@16: if (!(k & 1) || interval_lib::user::is_zero(x.lower())) // [-1,1]^/2 or [0,1] Chris@16: return I(static_cast(0), u, true); Chris@16: else // [-1,1]^/3 Chris@16: return I(-interval_lib::detail::root_aux_up(-x.lower(), k), u, true); Chris@16: else // [1,2] Chris@16: return I(interval_lib::detail::root_aux_dn(x.lower(), k), u, true); Chris@16: } Chris@16: Chris@16: } // namespace numeric Chris@16: } // namespace boost Chris@16: Chris@16: #endif // BOOST_NUMERIC_INTERVAL_ARITH2_HPP