Mercurial > octave-nkf
comparison scripts/general/quadl.m @ 13008:85dac13a911b
quadl.m: Fix integration with large error tolerances (Bug #33792)
quadl.m: Force recursion to occur at least once through global state variable.
Miscellaneous spacing changes to improve code appearance.
author | Rik <octave@nomad.inbox5.com> |
---|---|
date | Thu, 25 Aug 2011 09:51:27 -0700 |
parents | 412882f498b4 |
children | e81ddf9cacd5 |
comparison
equal
deleted
inserted
replaced
13006:61be447052c3 | 13008:85dac13a911b |
---|---|
60 ## 2004-02-10 Paul Kienzle | 60 ## 2004-02-10 Paul Kienzle |
61 ## * renamed to quadl for compatibility | 61 ## * renamed to quadl for compatibility |
62 ## * replace global variable terminate2 with local function need_warning | 62 ## * replace global variable terminate2 with local function need_warning |
63 ## * add paper ref to docs | 63 ## * add paper ref to docs |
64 | 64 |
65 function q = quadl (f, a, b, tol, trace, varargin) | 65 function q = quadl (f, a, b, tol = [], trace = false, varargin) |
66 need_warning (1); | 66 |
67 if (nargin < 4) | 67 if (nargin < 3) |
68 tol = []; | 68 print_usage (); |
69 endif | 69 endif |
70 if (nargin < 5) | 70 |
71 trace = []; | |
72 endif | |
73 if (isa (a, "single") || isa (b, "single")) | 71 if (isa (a, "single") || isa (b, "single")) |
74 myeps = eps ("single"); | 72 myeps = eps ("single"); |
75 else | 73 else |
76 myeps = eps; | 74 myeps = eps; |
77 endif | 75 endif |
78 if (isempty (tol)) | 76 if (isempty (tol)) |
79 tol = myeps; | 77 tol = myeps; |
80 endif | 78 endif |
81 if (isempty (trace)) | 79 if (isempty (trace)) |
82 trace = 0; | 80 trace = false; |
83 endif | 81 endif |
84 if (tol < myeps) | 82 if (tol < myeps) |
85 tol = myeps; | 83 tol = myeps; |
86 endif | 84 endif |
87 | 85 |
86 ## Track whether recursion has occurred | |
87 global __quadl_recurse_done__; | |
88 __quadl_recurse_done__ = false; | |
89 ## Track whether warning about machine precision has been issued | |
90 global __quadl_need_warning__; | |
91 __quadl_need_warning__ = true; | |
92 | |
88 m = (a+b)/2; | 93 m = (a+b)/2; |
89 h = (b-a)/2; | 94 h = (b-a)/2; |
90 alpha = sqrt(2/3); | 95 alpha = sqrt (2/3); |
91 beta = 1/sqrt(5); | 96 beta = 1/sqrt (5); |
92 | 97 |
93 x1 = .942882415695480; | 98 x1 = .942882415695480; |
94 x2 = .641853342345781; | 99 x2 = .641853342345781; |
95 x3 = .236383199662150; | 100 x3 = .236383199662150; |
96 | 101 |
102 fa = y(1); | 107 fa = y(1); |
103 fb = y(13); | 108 fb = y(13); |
104 | 109 |
105 i2 = (h/6)*(y(1) + y(13) + 5*(y(5)+y(9))); | 110 i2 = (h/6)*(y(1) + y(13) + 5*(y(5)+y(9))); |
106 | 111 |
107 i1 = (h/1470)*(77*(y(1)+y(13)) | 112 i1 = (h/1470)*( 77*(y(1)+y(13)) |
108 + 432*(y(3)+y(11)) | 113 + 432*(y(3)+y(11)) |
109 + 625*(y(5)+y(9)) | 114 + 625*(y(5)+y(9)) |
110 + 672*y(7)); | 115 + 672*y(7)); |
111 | 116 |
112 is = h*(.0158271919734802*(y(1)+y(13)) | 117 is = h*( .0158271919734802*(y(1)+y(13)) |
113 +.0942738402188500*(y(2)+y(12)) | 118 +.0942738402188500*(y(2)+y(12)) |
114 + .155071987336585*(y(3)+y(11)) | 119 + .155071987336585*(y(3)+y(11)) |
115 + .188821573960182*(y(4)+y(10)) | 120 + .188821573960182*(y(4)+y(10)) |
116 + .199773405226859*(y(5)+y(9)) | 121 + .199773405226859*(y(5)+y(9)) |
117 + .224926465333340*(y(6)+y(8)) | 122 + .224926465333340*(y(6)+y(8)) |
118 + .242611071901408*y(7)); | 123 + .242611071901408*y(7)); |
119 | 124 |
120 s = sign(is); | 125 s = sign (is); |
121 | |
122 if (s == 0) | 126 if (s == 0) |
123 s = 1; | 127 s = 1; |
124 endif | 128 endif |
125 erri1 = abs(i1-is); | 129 erri1 = abs (i1-is); |
126 erri2 = abs(i2-is); | 130 erri2 = abs (i2-is); |
127 R = 1; | |
128 if (erri2 != 0) | 131 if (erri2 != 0) |
129 R = erri1/erri2; | 132 R = erri1/erri2; |
133 else | |
134 R = 1; | |
130 endif | 135 endif |
131 if (R > 0 && R < 1) | 136 if (R > 0 && R < 1) |
132 tol = tol/R; | 137 tol = tol/R; |
133 endif | 138 endif |
134 is = s*abs(is)*tol/myeps; | 139 is = s * abs(is) * tol/myeps; |
135 if (is == 0) | 140 if (is == 0) |
136 is = b-a; | 141 is = b-a; |
137 endif | 142 endif |
143 | |
138 q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin{:}); | 144 q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin{:}); |
145 | |
139 endfunction | 146 endfunction |
140 | 147 |
141 ## ADAPTLOBSTP Recursive function used by QUADL. | 148 ## ADAPTLOBSTP Recursive function used by QUADL. |
142 ## | 149 ## |
143 ## Q = ADAPTLOBSTP('F', A, B, FA, FB, IS, TRACE) tries to | 150 ## Q = ADAPTLOBSTP('F', A, B, FA, FB, IS, TRACE) tries to |
144 ## approximate the integral of F(X) from A to B to | 151 ## approximate the integral of F(X) from A to B to |
145 ## an appropriate relative error. The argument 'F' is | 152 ## an appropriate relative error. The argument 'F' is |
146 ## a string containing the name of f. The remaining | 153 ## a string containing the name of f. The remaining |
147 ## arguments are generated by ADAPTLOB or by recursion. | 154 ## arguments are generated by ADAPTLOB or by recursion. |
148 ## | 155 ## |
149 ## Walter Gautschi, 08/03/98 | 156 ## Walter Gautschi, 08/03/98 |
150 | 157 |
151 function q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin) | 158 function q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin) |
159 global __quadl_recurse_done__; | |
160 global __quadl_need_warning__; | |
161 | |
152 h = (b-a)/2; | 162 h = (b-a)/2; |
153 m = (a+b)/2; | 163 m = (a+b)/2; |
154 alpha = sqrt(2/3); | 164 alpha = sqrt (2/3); |
155 beta = 1/sqrt(5); | 165 beta = 1 / sqrt(5); |
156 mll = m-alpha*h; | 166 mll = m-alpha*h; |
157 ml = m-beta*h; | 167 ml = m-beta*h; |
158 mr = m+beta*h; | 168 mr = m+beta*h; |
159 mrr = m+alpha*h; | 169 mrr = m+alpha*h; |
160 x = [mll, ml, m, mr, mrr]; | 170 x = [mll, ml, m, mr, mrr]; |
161 y = feval(f, x, varargin{:}); | 171 y = feval (f, x, varargin{:}); |
162 fmll = y(1); | 172 fmll = y(1); |
163 fml = y(2); | 173 fml = y(2); |
164 fm = y(3); | 174 fm = y(3); |
165 fmr = y(4); | 175 fmr = y(4); |
166 fmrr = y(5); | 176 fmrr = y(5); |
167 i2 = (h/6)*(fa + fb + 5*(fml+fmr)); | 177 i2 = (h/6)*(fa + fb + 5*(fml+fmr)); |
168 i1 = (h/1470)*(77*(fa+fb) + 432*(fmll+fmrr) + 625*(fml+fmr) + 672*fm); | 178 i1 = (h/1470)*(77*(fa+fb) + 432*(fmll+fmrr) + 625*(fml+fmr) + 672*fm); |
169 if (is+(i1-i2) == is || mll <= a || b <= mrr) | 179 if ((is+(i1-i2) == is || mll <= a || b <= mrr) && __quadl_recurse_done__) |
170 if ((m <= a || b <= m) && need_warning ()) | 180 if ((m <= a || b <= m) && __quadl_need_warning__) |
171 warning ("quadl: interval contains no more machine number"); | 181 warning ("quadl: interval contains no more machine number"); |
172 warning ("quadl: required tolerance may not be met"); | 182 warning ("quadl: required tolerance may not be met"); |
173 need_warning (0); | 183 __quadl_need_warning__ = false; |
174 endif | 184 endif |
175 q = i1; | 185 q = i1; |
176 if (trace) | 186 if (trace) |
177 disp ([a, b-a, q]); | 187 disp ([a, b-a, q]); |
178 endif | 188 endif |
179 else | 189 else |
180 q = (adaptlobstp (f, a, mll, fa, fmll, is, trace, varargin{:}) | 190 __quadl_recurse_done__ = true; |
181 + adaptlobstp (f, mll, ml, fmll, fml, is, trace, varargin{:}) | 191 q = ( adaptlobstp (f, a , mll, fa , fmll, is, trace, varargin{:}) |
182 + adaptlobstp (f, ml, m, fml, fm, is, trace, varargin{:}) | 192 + adaptlobstp (f, mll, ml , fmll, fml , is, trace, varargin{:}) |
183 + adaptlobstp (f, m, mr, fm, fmr, is, trace, varargin{:}) | 193 + adaptlobstp (f, ml , m , fml , fm , is, trace, varargin{:}) |
184 + adaptlobstp (f, mr, mrr, fmr, fmrr, is, trace, varargin{:}) | 194 + adaptlobstp (f, m , mr , fm , fmr , is, trace, varargin{:}) |
185 + adaptlobstp (f, mrr, b, fmrr, fb, is, trace, varargin{:})); | 195 + adaptlobstp (f, mr , mrr, fmr , fmrr, is, trace, varargin{:}) |
196 + adaptlobstp (f, mrr, b , fmrr, fb , is, trace, varargin{:})); | |
186 endif | 197 endif |
187 endfunction | 198 endfunction |
188 | 199 |
189 function r = need_warning (v) | |
190 persistent w = []; | |
191 if (nargin == 0) | |
192 r = w; | |
193 else | |
194 w = v; | |
195 endif | |
196 endfunction | |
197 | |
198 | 200 |
199 ## basic functionality | 201 ## basic functionality |
200 %!assert( quadl (@(x) sin (x), 0, pi, [], []), 2, -3e-16) | 202 %!assert (quadl (@(x) sin (x), 0, pi, [], []), 2, -3e-16) |
201 | 203 |
202 ## the values here are very high so it may be unavoidable that this fails | 204 ## the values here are very high so it may be unavoidable that this fails |
203 %!assert ( quadl (@(x) sin (3*x).*cosh (x).*sinh (x),10,15), | 205 %!assert (quadl (@(x) sin (3*x).*cosh (x).*sinh (x),10,15), |
204 %! 2.588424538641647e+10, -9e-15) | 206 %! 2.588424538641647e+10, -9e-15) |
205 | 207 |
206 ## extra parameters | 208 ## extra parameters |
207 %!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3), | 209 %!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3), |
208 %! cos(2)/3 - cos(5)/3, - 3e-16) | 210 %! cos(2)/3 - cos(5)/3, - 3e-16) |
209 | 211 |
210 ## test different tolerances. This test currently fails for a very high | 212 ## test different tolerances. |
211 ## tolerances. | 213 %!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.3, []), |
212 %!assert ( quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.3, []), | |
213 %! (60 + sin(4) - sin(64))/12, -0.3) | 214 %! (60 + sin(4) - sin(64))/12, -0.3) |
214 | 215 %!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []), |
215 | |
216 ## for lower tolerances the test passes. | |
217 %!assert ( quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []), | |
218 %! (60 + sin(4) - sin(64))/12, -0.1) | 216 %! (60 + sin(4) - sin(64))/12, -0.1) |
217 |