123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- #ifndef BOOST_MATH_TOOLS_CONDITION_NUMBERS_HPP
- #define BOOST_MATH_TOOLS_CONDITION_NUMBERS_HPP
- #include <cmath>
- #include <limits>
- #include <boost/math/differentiation/finite_difference.hpp>
- #include <boost/math/tools/config.hpp>
- namespace boost { namespace math { namespace tools {
- template<class Real, bool kahan=true>
- class summation_condition_number {
- public:
- summation_condition_number(Real const x = 0)
- {
- using std::abs;
- m_l1 = abs(x);
- m_sum = x;
- m_c = 0;
- }
- void operator+=(Real const & x)
- {
- using std::abs;
-
- m_l1 += abs(x);
- BOOST_MATH_IF_CONSTEXPR (kahan)
- {
- Real y = x - m_c;
- Real t = m_sum + y;
- m_c = (t-m_sum) -y;
- m_sum = t;
- }
- else
- {
- m_sum += x;
- }
- }
- inline void operator-=(Real const & x)
- {
- this->operator+=(-x);
- }
-
-
-
-
- Real operator()() const
- {
- using std::abs;
- if (m_sum == Real(0) && m_l1 != Real(0))
- {
- return std::numeric_limits<Real>::infinity();
- }
- return m_l1/abs(m_sum);
- }
- Real sum() const
- {
-
-
-
- return m_sum + m_c;
- }
- Real l1_norm() const
- {
- return m_l1;
- }
- private:
- Real m_l1;
- Real m_sum;
- Real m_c;
- };
- template<class F, class Real>
- Real evaluation_condition_number(F const & f, Real const & x)
- {
- using std::abs;
- using std::isnan;
- using std::sqrt;
- using boost::math::differentiation::finite_difference_derivative;
- Real fx = f(x);
- if (isnan(fx))
- {
- return std::numeric_limits<Real>::quiet_NaN();
- }
- bool caught_exception = false;
- Real fp;
- #ifndef BOOST_MATH_NO_EXCEPTIONS
- try
- {
- #endif
- fp = finite_difference_derivative(f, x);
- #ifndef BOOST_MATH_NO_EXCEPTIONS
- }
- catch(...)
- {
- caught_exception = true;
- }
- #endif
- if (isnan(fp) || caught_exception)
- {
-
- fp = finite_difference_derivative<decltype(f), Real, 1>(f, x);
- if (isnan(fp))
- {
-
- const Real eps = (std::numeric_limits<Real>::epsilon)();
- Real h = - 2 * sqrt(eps);
- h = boost::math::differentiation::detail::make_xph_representable(x, h);
- Real yh = f(x + h);
- Real y0 = f(x);
- Real diff = yh - y0;
- fp = diff / h;
- if (isnan(fp))
- {
- return std::numeric_limits<Real>::quiet_NaN();
- }
- }
- }
- if (fx == 0)
- {
- if (x==0 || fp==0)
- {
- return std::numeric_limits<Real>::quiet_NaN();
- }
- return std::numeric_limits<Real>::infinity();
- }
- return abs(x*fp/fx);
- }
- }}}
- #endif
|