condition_numbers.qbk 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. [/
  2. Copyright (c) 2019 Nick Thompson
  3. Use, modification and distribution are subject to the
  4. Boost Software License, Version 1.0. (See accompanying file
  5. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ]
  7. [section:cond Condition Numbers]
  8. [heading Synopsis]
  9. ``
  10. #include <boost/math/tools/condition_numbers.hpp>
  11. namespace boost::math::tools {
  12. template<class Real, bool kahan=true>
  13. class summation_condition_number {
  14. public:
  15. summation_condition_number(Real const x = 0);
  16. void operator+=(Real const & x);
  17. inline void operator-=(Real const & x);
  18. [[nodiscard]] Real operator()() const;
  19. [[nodiscard]] Real sum() const;
  20. [[nodiscard]] Real l1_norm() const;
  21. };
  22. template<class F, class Real>
  23. auto evaluation_condition_number(F const & f, Real const & x);
  24. } // namespaces
  25. ``
  26. [heading Summation Condition Number]
  27. Here we compute the condition number of the alternating harmonic sum:
  28. using boost::math::tools::summation_condition_number;
  29. auto cond = summation_condition_number<float, /* kahan = */ false>();
  30. float max_n = 10000000;
  31. for (float n = 1; n < max_n; n += 2)
  32. {
  33. cond += 1/n;
  34. cond -= 1/(n+1);
  35. }
  36. std::cout << std::setprecision(std::numeric_limits<float>::digits10);
  37. std::cout << "ln(2) = " << boost::math::constants::ln_two<float>() << "\n";
  38. std::cout << "Sum = " << cond.sum() << "\n";
  39. std::cout << "Condition number = " << cond() << "\n";
  40. Output:
  41. ln(2) = 0.693147
  42. Sum = 0.693137
  43. Condition number = 22.22282
  44. We see that we have lost roughly two digits of accuracy,
  45. consistent with the heuristic that if the condition number is 10[super /k/],
  46. then we lose /k/ significant digits in the sum.
  47. Our guess it that if you're worried about whether your sum is ill-conditioned,
  48. the /last/ thing you want is for your condition number estimate to be inaccurate as well.
  49. Since the condition number estimate relies on computing the (perhaps ill-conditioned) sum,
  50. we have defaulted the accumulation to use Kahan summation:
  51. auto cond = boost::math::tools::summation_condition_number<float>(); // will use Kahan summation.
  52. // ...
  53. Output:
  54. ln(2) = 0.693147
  55. Kahan sum = 0.693147
  56. Condition number = 22.2228
  57. If you are interested, the L[sub 1] norm is also generated by this computation, so you may query it if you like:
  58. float l1 = cond.l1_norm();
  59. // l1 = 15.4
  60. [heading Condition Number of Function Evaluation]
  61. The [@https://en.wikipedia.org/wiki/Condition_number condition number] of function evaluation is defined as the absolute value of /xf/'(/x/)/f/(/x/)[super -1].
  62. It is computed as follows:
  63. using boost::math::tools::evaluation_condition_number;
  64. auto f = [](double x)->double { return std::log(x); };
  65. double x = 1.125;
  66. double cond = evaluation_condition_number(f, 1.125);
  67. // cond = 1/log(x)
  68. [heading Caveats]
  69. The condition number of function evaluation gives us a measure of how sensitive our function is to roundoff error.
  70. Unfortunately, evaluating the condition number requires evaluating the function and its derivative,
  71. and this calculation is itself inaccurate whenever the condition number of function evaluation is large.
  72. Sadly, this is also the regime when you are most interested in evaluating a condition number!
  73. This seems to be a fundamental problem.
  74. However, it should not be necessary to evaluate the condition number to high accuracy,
  75. valuable insights can be obtained simply by looking at the change in condition number as the function
  76. evolves over its domain.
  77. [heading References]
  78. * Gautschi, Walter. ['Orthogonal polynomials: computation and approximation] Oxford University Press on Demand, 2004.
  79. * Higham, Nicholas J. ['The accuracy of floating point summation.] SIAM Journal on Scientific Computing 14.4 (1993): 783-799.
  80. * Higham, Nicholas J. ['Accuracy and stability of numerical algorithms.] Vol. 80. Siam, 2002.
  81. [endsect]