1 | /* Boost example/newton-raphson.cpp |
---|
2 | * Newton iteration for intervals |
---|
3 | * |
---|
4 | * Copyright 2003 Guillaume Melquiond |
---|
5 | * |
---|
6 | * Distributed under the Boost Software License, Version 1.0. |
---|
7 | * (See accompanying file LICENSE_1_0.txt or |
---|
8 | * copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
9 | */ |
---|
10 | |
---|
11 | #include <boost/numeric/interval.hpp> |
---|
12 | #include <vector> |
---|
13 | #include <algorithm> |
---|
14 | #include <utility> |
---|
15 | #include <iostream> |
---|
16 | #include <iomanip> |
---|
17 | |
---|
18 | template <class I> I f(const I& x) |
---|
19 | { return x * (x - 1.) * (x - 2.) * (x - 3.) * (x - 4.); } |
---|
20 | template <class I> I f_diff(const I& x) |
---|
21 | { return (((5. * x - 40.) * x + 105.) * x - 100.) * x + 24.; } |
---|
22 | |
---|
23 | static const double max_width = 1e-10; |
---|
24 | static const double alpha = 0.75; |
---|
25 | |
---|
26 | using namespace boost; |
---|
27 | using namespace numeric; |
---|
28 | using namespace interval_lib; |
---|
29 | |
---|
30 | // First method: no empty intervals |
---|
31 | |
---|
32 | typedef interval<double> I1_aux; |
---|
33 | typedef unprotect<I1_aux>::type I1; |
---|
34 | |
---|
35 | std::vector<I1> newton_raphson(const I1& xs) { |
---|
36 | std::vector<I1> l, res; |
---|
37 | I1 vf, vd, x, x1, x2; |
---|
38 | l.push_back(xs); |
---|
39 | while (!l.empty()) { |
---|
40 | x = l.back(); |
---|
41 | l.pop_back(); |
---|
42 | bool x2_used; |
---|
43 | double xx = median(x); |
---|
44 | vf = f<I1>(xx); |
---|
45 | vd = f_diff<I1>(x); |
---|
46 | if (in_zero(vf) && in_zero(vd)) { |
---|
47 | x1 = I1::whole(); |
---|
48 | x2_used = false; |
---|
49 | } else { |
---|
50 | x1 = xx - division_part1(vf, vd, x2_used); |
---|
51 | if (x2_used) x2 = xx - division_part2(vf, vd); |
---|
52 | } |
---|
53 | if (overlap(x1, x)) x1 = intersect(x, x1); |
---|
54 | else if (x2_used) { x1 = x2; x2_used = false; } |
---|
55 | else continue; |
---|
56 | if (x2_used) |
---|
57 | if (overlap(x2, x)) x2 = intersect(x, x2); |
---|
58 | else x2_used = false; |
---|
59 | if (x2_used && width(x2) > width(x1)) std::swap(x1, x2); |
---|
60 | if (!in_zero(f(x1))) |
---|
61 | if (x2_used) { x1 = x2; x2_used = false; } |
---|
62 | else continue; |
---|
63 | if (width(x1) < max_width) res.push_back(x1); |
---|
64 | else if (width(x1) > alpha * width(x)) { |
---|
65 | std::pair<I1, I1> p = bisect(x); |
---|
66 | if (in_zero(f(p.first))) l.push_back(p.first); |
---|
67 | x2 = p.second; |
---|
68 | x2_used = true; |
---|
69 | } else l.push_back(x1); |
---|
70 | if (x2_used && in_zero(f(x2))) |
---|
71 | if (width(x2) < max_width) res.push_back(x2); |
---|
72 | else l.push_back(x2); |
---|
73 | } |
---|
74 | return res; |
---|
75 | } |
---|
76 | |
---|
77 | // Second method: with empty intervals |
---|
78 | |
---|
79 | typedef change_checking<I1_aux, checking_no_nan<double> >::type I2_aux; |
---|
80 | typedef unprotect<I2_aux>::type I2; |
---|
81 | |
---|
82 | std::vector<I2> newton_raphson(const I2& xs) { |
---|
83 | std::vector<I2> l, res; |
---|
84 | I2 vf, vd, x, x1, x2; |
---|
85 | l.push_back(xs); |
---|
86 | while (!l.empty()) { |
---|
87 | x = l.back(); |
---|
88 | l.pop_back(); |
---|
89 | double xx = median(x); |
---|
90 | vf = f<I2>(xx); |
---|
91 | vd = f_diff<I2>(x); |
---|
92 | if (in_zero(vf) && in_zero(vd)) { |
---|
93 | x1 = x; |
---|
94 | x2 = I2::empty(); |
---|
95 | } else { |
---|
96 | bool x2_used; |
---|
97 | x1 = intersect(x, xx - division_part1(vf, vd, x2_used)); |
---|
98 | x2 = intersect(x, xx - division_part2(vf, vd, x2_used)); |
---|
99 | } |
---|
100 | if (width(x2) > width(x1)) std::swap(x1, x2); |
---|
101 | if (empty(x1) || !in_zero(f(x1))) |
---|
102 | if (!empty(x2)) { x1 = x2; x2 = I2::empty(); } |
---|
103 | else continue; |
---|
104 | if (width(x1) < max_width) res.push_back(x1); |
---|
105 | else if (width(x1) > alpha * width(x)) { |
---|
106 | std::pair<I2, I2> p = bisect(x); |
---|
107 | if (in_zero(f(p.first))) l.push_back(p.first); |
---|
108 | x2 = p.second; |
---|
109 | } else l.push_back(x1); |
---|
110 | if (!empty(x2) && in_zero(f(x2))) |
---|
111 | if (width(x2) < max_width) res.push_back(x2); |
---|
112 | else l.push_back(x2); |
---|
113 | } |
---|
114 | return res; |
---|
115 | } |
---|
116 | |
---|
117 | template<class T, class Policies> |
---|
118 | std::ostream &operator<<(std::ostream &os, |
---|
119 | const boost::numeric::interval<T, Policies> &x) { |
---|
120 | os << "[" << x.lower() << ", " << x.upper() << "]"; |
---|
121 | return os; |
---|
122 | } |
---|
123 | |
---|
124 | int main() { |
---|
125 | { |
---|
126 | I1_aux::traits_type::rounding rnd; |
---|
127 | std::vector<I1> res = newton_raphson(I1(-1, 5.1)); |
---|
128 | std::cout << "Results: " << std::endl << std::setprecision(12); |
---|
129 | for(std::vector<I1>::const_iterator i = res.begin(); i != res.end(); ++i) |
---|
130 | std::cout << " " << *i << std::endl; |
---|
131 | std::cout << std::endl; |
---|
132 | } |
---|
133 | { |
---|
134 | I2_aux::traits_type::rounding rnd; |
---|
135 | std::vector<I2> res = newton_raphson(I2(-1, 5.1)); |
---|
136 | std::cout << "Results: " << std::endl << std::setprecision(12); |
---|
137 | for(std::vector<I2>::const_iterator i = res.begin(); i != res.end(); ++i) |
---|
138 | std::cout << " " << *i << std::endl; |
---|
139 | std::cout << std::endl; |
---|
140 | } |
---|
141 | } |
---|