os/ossrv/ossrv_pub/boost_apis/boost/numeric/interval/arith2.hpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* Boost interval/arith2.hpp template implementation file
sl@0
     2
 *
sl@0
     3
 * This header provides some auxiliary arithmetic
sl@0
     4
 * functions: fmod, sqrt, square, pov, inverse and
sl@0
     5
 * a multi-interval division.
sl@0
     6
 *
sl@0
     7
 * Copyright 2002-2003 Hervé Brönnimann, Guillaume Melquiond, Sylvain Pion
sl@0
     8
 *
sl@0
     9
 * Distributed under the Boost Software License, Version 1.0.
sl@0
    10
 * (See accompanying file LICENSE_1_0.txt or
sl@0
    11
 * copy at http://www.boost.org/LICENSE_1_0.txt)
sl@0
    12
 */
sl@0
    13
sl@0
    14
#ifndef BOOST_NUMERIC_INTERVAL_ARITH2_HPP
sl@0
    15
#define BOOST_NUMERIC_INTERVAL_ARITH2_HPP
sl@0
    16
sl@0
    17
#include <boost/config.hpp>
sl@0
    18
#include <boost/numeric/interval/detail/interval_prototype.hpp>
sl@0
    19
#include <boost/numeric/interval/detail/test_input.hpp>
sl@0
    20
#include <boost/numeric/interval/detail/bugs.hpp>
sl@0
    21
#include <boost/numeric/interval/detail/division.hpp>
sl@0
    22
#include <boost/numeric/interval/arith.hpp>
sl@0
    23
#include <boost/numeric/interval/policies.hpp>
sl@0
    24
#include <algorithm>
sl@0
    25
#include <cmath>
sl@0
    26
sl@0
    27
namespace boost {
sl@0
    28
namespace numeric {
sl@0
    29
sl@0
    30
template<class T, class Policies> inline
sl@0
    31
interval<T, Policies> fmod(const interval<T, Policies>& x,
sl@0
    32
                           const interval<T, Policies>& y)
sl@0
    33
{
sl@0
    34
  if (interval_lib::detail::test_input(x, y))
sl@0
    35
    return interval<T, Policies>::empty();
sl@0
    36
  typename Policies::rounding rnd;
sl@0
    37
  typedef typename interval_lib::unprotect<interval<T, Policies> >::type I;
sl@0
    38
  T const &yb = interval_lib::user::is_neg(x.lower()) ? y.lower() : y.upper();
sl@0
    39
  T n = rnd.int_down(rnd.div_down(x.lower(), yb));
sl@0
    40
  return (const I&)x - n * (const I&)y;
sl@0
    41
}
sl@0
    42
sl@0
    43
template<class T, class Policies> inline
sl@0
    44
interval<T, Policies> fmod(const interval<T, Policies>& x, const T& y)
sl@0
    45
{
sl@0
    46
  if (interval_lib::detail::test_input(x, y))
sl@0
    47
    return interval<T, Policies>::empty();
sl@0
    48
  typename Policies::rounding rnd;
sl@0
    49
  typedef typename interval_lib::unprotect<interval<T, Policies> >::type I;
sl@0
    50
  T n = rnd.int_down(rnd.div_down(x.lower(), y));
sl@0
    51
  return (const I&)x - n * I(y);
sl@0
    52
}
sl@0
    53
sl@0
    54
template<class T, class Policies> inline
sl@0
    55
interval<T, Policies> fmod(const T& x, const interval<T, Policies>& y)
sl@0
    56
{
sl@0
    57
  if (interval_lib::detail::test_input(x, y))
sl@0
    58
    return interval<T, Policies>::empty();
sl@0
    59
  typename Policies::rounding rnd;
sl@0
    60
  typedef typename interval_lib::unprotect<interval<T, Policies> >::type I;
sl@0
    61
  T const &yb = interval_lib::user::is_neg(x) ? y.lower() : y.upper();
sl@0
    62
  T n = rnd.int_down(rnd.div_down(x, yb));
sl@0
    63
  return x - n * (const I&)y;
sl@0
    64
}
sl@0
    65
sl@0
    66
namespace interval_lib {
sl@0
    67
sl@0
    68
template<class T, class Policies> inline
sl@0
    69
interval<T, Policies> division_part1(const interval<T, Policies>& x,
sl@0
    70
                                     const interval<T, Policies>& y, bool& b)
sl@0
    71
{
sl@0
    72
  typedef interval<T, Policies> I;
sl@0
    73
  b = false;
sl@0
    74
  if (detail::test_input(x, y))
sl@0
    75
    return I::empty();
sl@0
    76
  if (zero_in(y))
sl@0
    77
    if (!user::is_zero(y.lower()))
sl@0
    78
      if (!user::is_zero(y.upper()))
sl@0
    79
        return detail::div_zero_part1(x, y, b);
sl@0
    80
      else
sl@0
    81
        return detail::div_negative(x, y.lower());
sl@0
    82
    else
sl@0
    83
      if (!user::is_zero(y.upper()))
sl@0
    84
        return detail::div_positive(x, y.upper());
sl@0
    85
      else
sl@0
    86
        return I::empty();
sl@0
    87
  else
sl@0
    88
    return detail::div_non_zero(x, y);
sl@0
    89
}
sl@0
    90
sl@0
    91
template<class T, class Policies> inline
sl@0
    92
interval<T, Policies> division_part2(const interval<T, Policies>& x,
sl@0
    93
                                     const interval<T, Policies>& y, bool b = true)
sl@0
    94
{
sl@0
    95
  if (!b) return interval<T, Policies>::empty();
sl@0
    96
  return detail::div_zero_part2(x, y);
sl@0
    97
}
sl@0
    98
sl@0
    99
template<class T, class Policies> inline
sl@0
   100
interval<T, Policies> multiplicative_inverse(const interval<T, Policies>& x)
sl@0
   101
{
sl@0
   102
  typedef interval<T, Policies> I;
sl@0
   103
  if (detail::test_input(x))
sl@0
   104
    return I::empty();
sl@0
   105
  T one = static_cast<T>(1);
sl@0
   106
  typename Policies::rounding rnd;
sl@0
   107
  if (zero_in(x)) {
sl@0
   108
    typedef typename Policies::checking checking;
sl@0
   109
    if (!user::is_zero(x.lower()))
sl@0
   110
      if (!user::is_zero(x.upper()))
sl@0
   111
        return I::whole();
sl@0
   112
      else
sl@0
   113
        return I(checking::neg_inf(), rnd.div_up(one, x.lower()), true);
sl@0
   114
    else
sl@0
   115
      if (!user::is_zero(x.upper()))
sl@0
   116
        return I(rnd.div_down(one, x.upper()), checking::pos_inf(), true);
sl@0
   117
      else
sl@0
   118
        return I::empty();
sl@0
   119
  } else 
sl@0
   120
    return I(rnd.div_down(one, x.upper()), rnd.div_up(one, x.lower()), true);
sl@0
   121
}
sl@0
   122
sl@0
   123
namespace detail {
sl@0
   124
sl@0
   125
template<class T, class Rounding> inline
sl@0
   126
T pow_dn(const T& x_, int pwr, Rounding& rnd) // x and pwr are positive
sl@0
   127
{
sl@0
   128
  T x = x_;
sl@0
   129
  T y = (pwr & 1) ? x_ : static_cast<T>(1);
sl@0
   130
  pwr >>= 1;
sl@0
   131
  while (pwr > 0) {
sl@0
   132
    x = rnd.mul_down(x, x);
sl@0
   133
    if (pwr & 1) y = rnd.mul_down(x, y);
sl@0
   134
    pwr >>= 1;
sl@0
   135
  }
sl@0
   136
  return y;
sl@0
   137
}
sl@0
   138
sl@0
   139
template<class T, class Rounding> inline
sl@0
   140
T pow_up(const T& x_, int pwr, Rounding& rnd) // x and pwr are positive
sl@0
   141
{
sl@0
   142
  T x = x_;
sl@0
   143
  T y = (pwr & 1) ? x_ : static_cast<T>(1);
sl@0
   144
  pwr >>= 1;
sl@0
   145
  while (pwr > 0) {
sl@0
   146
    x = rnd.mul_up(x, x);
sl@0
   147
    if (pwr & 1) y = rnd.mul_up(x, y);
sl@0
   148
    pwr >>= 1;
sl@0
   149
  }
sl@0
   150
  return y;
sl@0
   151
}
sl@0
   152
sl@0
   153
} // namespace detail
sl@0
   154
} // namespace interval_lib
sl@0
   155
sl@0
   156
template<class T, class Policies> inline
sl@0
   157
interval<T, Policies> pow(const interval<T, Policies>& x, int pwr)
sl@0
   158
{
sl@0
   159
  BOOST_USING_STD_MAX();
sl@0
   160
  using interval_lib::detail::pow_dn;
sl@0
   161
  using interval_lib::detail::pow_up;
sl@0
   162
  typedef interval<T, Policies> I;
sl@0
   163
sl@0
   164
  if (interval_lib::detail::test_input(x))
sl@0
   165
    return I::empty();
sl@0
   166
sl@0
   167
  if (pwr == 0)
sl@0
   168
    if (interval_lib::user::is_zero(x.lower())
sl@0
   169
        && interval_lib::user::is_zero(x.upper()))
sl@0
   170
      return I::empty();
sl@0
   171
    else
sl@0
   172
      return I(static_cast<T>(1));
sl@0
   173
  else if (pwr < 0)
sl@0
   174
    return interval_lib::multiplicative_inverse(pow(x, -pwr));
sl@0
   175
sl@0
   176
  typename Policies::rounding rnd;
sl@0
   177
  
sl@0
   178
  if (interval_lib::user::is_neg(x.upper())) {        // [-2,-1]
sl@0
   179
    T yl = pow_dn(static_cast<T>(-x.upper()), pwr, rnd);
sl@0
   180
    T yu = pow_up(static_cast<T>(-x.lower()), pwr, rnd);
sl@0
   181
    if (pwr & 1)     // [-2,-1]^1
sl@0
   182
      return I(-yu, -yl, true);
sl@0
   183
    else             // [-2,-1]^2
sl@0
   184
      return I(yl, yu, true);
sl@0
   185
  } else if (interval_lib::user::is_neg(x.lower())) { // [-1,1]
sl@0
   186
    if (pwr & 1) {   // [-1,1]^1
sl@0
   187
      return I(-pow_up(-x.lower(), pwr, rnd), pow_up(x.upper(), pwr, rnd), true);
sl@0
   188
    } else {         // [-1,1]^2
sl@0
   189
      return I(static_cast<T>(0), pow_up(max BOOST_PREVENT_MACRO_SUBSTITUTION(static_cast<T>(-x.lower()), x.upper()), pwr, rnd), true);
sl@0
   190
    }
sl@0
   191
  } else {                                // [1,2]
sl@0
   192
    return I(pow_dn(x.lower(), pwr, rnd), pow_up(x.upper(), pwr, rnd), true);
sl@0
   193
  }
sl@0
   194
}
sl@0
   195
sl@0
   196
template<class T, class Policies> inline
sl@0
   197
interval<T, Policies> sqrt(const interval<T, Policies>& x)
sl@0
   198
{
sl@0
   199
  typedef interval<T, Policies> I;
sl@0
   200
  if (interval_lib::detail::test_input(x) || interval_lib::user::is_neg(x.upper()))
sl@0
   201
    return I::empty();
sl@0
   202
  typename Policies::rounding rnd;
sl@0
   203
  T l = !interval_lib::user::is_pos(x.lower()) ? static_cast<T>(0) : rnd.sqrt_down(x.lower());
sl@0
   204
  return I(l, rnd.sqrt_up(x.upper()), true);
sl@0
   205
}
sl@0
   206
sl@0
   207
template<class T, class Policies> inline
sl@0
   208
interval<T, Policies> square(const interval<T, Policies>& x)
sl@0
   209
{
sl@0
   210
  typedef interval<T, Policies> I;
sl@0
   211
  if (interval_lib::detail::test_input(x))
sl@0
   212
    return I::empty();
sl@0
   213
  typename Policies::rounding rnd;
sl@0
   214
  const T& xl = x.lower();
sl@0
   215
  const T& xu = x.upper();
sl@0
   216
  if (interval_lib::user::is_neg(xu))
sl@0
   217
    return I(rnd.mul_down(xu, xu), rnd.mul_up(xl, xl), true);
sl@0
   218
  else if (interval_lib::user::is_pos(x.lower()))
sl@0
   219
    return I(rnd.mul_down(xl, xl), rnd.mul_up(xu, xu), true);
sl@0
   220
  else
sl@0
   221
    return I(static_cast<T>(0), (-xl > xu ? rnd.mul_up(xl, xl) : rnd.mul_up(xu, xu)), true);
sl@0
   222
}
sl@0
   223
sl@0
   224
} // namespace numeric
sl@0
   225
} // namespace boost
sl@0
   226
sl@0
   227
#endif // BOOST_NUMERIC_INTERVAL_ARITH2_HPP