Function: romberg (expr, x, a, b)
Function: romberg (expr, a, b)
Romberg integration. There are two
ways to use this function. The first is an inefficient way like the definite
integral version of integrate: romberg
(<integrand>, <variable of integration>, <lower limit>,
<upper limit>).
Examples:
|
|
(%i1) showtime: true$(%i2) romberg (sin(y), y, 0, %pi);Evaluation took 0.00 seconds (0.01 elapsed) using 25.293 KB.(%o2) 2.000000016288042(%i3) 1/((x-1)^2+1/100) + 1/((x-2)^2+1/1000) + 1/((x-3)^2+1/200)$(%i4) f(x) := ''%$(%i5) rombergtol: 1e-6$(%i6) rombergit: 15$(%i7) romberg (f(x), x, -5, 5);Evaluation took 11.97 seconds (12.21 elapsed) using 12.423 MB.(%o7) 173.6730736617464 |
The second is an efficient way that is used as follows:
|
|
romberg (<function name>, <lower limit>, <upper limit>); |
Continuing the above example, we have:
|
|
(%i8) f(x) := (mode_declare ([function(f), x], float), ''(%th(5)))$(%i9) translate(f);(%o9) [f](%i10) romberg (f, -5, 5);Evaluation took 3.51 seconds (3.86 elapsed) using 6.641 MB.(%o10) 173.6730736617464 |
The first argument must be a
translated or compiled function. (If it is compiled it must be declared to
return a flonum.) If the first argument is not already translated, romberg will not
attempt to translate it but will give an error.
The accuracy of the integration is
governed by the global variables rombergtol (default value 1.E-4) and rombergit (default
value 11). romberg will return a result if the relative difference in successive
approximations is less than rombergtol. It will try halving the stepsize rombergit times before it
gives up. The number of iterations and function evaluations which romberg will do is
governed by rombergabs and rombergmin.
romberg may be called recursively and thus can do double and triple integrals.
Example:
|
|
(%i1) assume (x > 0)$(%i2) integrate (integrate (x*y/(x+y), y, 0, x/2), x, 1, 3)$(%i3) radcan (%); 26 log(3) - 26 log(2) - 13(%o3) - -------------------------- 3(%i4) %,numer;(%o4) .8193023963959073(%i5) define_variable (x, 0.0, float, "Global variable in function F")$(%i6) f(y) := (mode_declare (y, float), x*y/(x+y))$(%i7) g(x) := romberg ('f, 0, x/2)$ (%i8) romberg (g, 1, 3);(%o8) .8193022864324522 |
The advantage with this way is that
the function f can be used for other purposes, like plotting. The disadvantage is
that you have to think up a name for both the function f and its free
variable x. Or, without the global:
|
|
(%i1) g_1(x) := (mode_declare (x, float), romberg (x*y/(x+y), y, 0, x/2))$(%i2) romberg (g_1, 1, 3);(%o2) .8193022864324522 |
The advantage here is shortness.
|
|
(%i3) q (a, b) := romberg (romberg (x*y/(x+y), y, 0, x/2), x, a, b)$(%i4) q (1, 3);(%o4) .8193022864324522 |
It is even shorter this way, and the
variables do not need to be declared because they are in the context of romberg. Use of romberg for
multiple integrals can have great disadvantages, though. The amount of extra
calculation needed because of the geometric information thrown away by
expressing multiple integrals this way can be incredible. The user should be
sure to understand and use the rombergtol and rombergit switches.
Default value: 0.0
Assuming that successive estimates
produced by romberg are y[0], y[1], y[2], etc., then romberg will return after n iterations if (roughly speaking)
|
|
(abs(y[n]-y[n-1]) <= rombergabs or abs(y[n]-y[n-1])/(if y[n]=0.0 then 1.0 else y[n]) <= rombergtol) |
is true. (The condition on
the number of iterations given by rombergmin must also be satisfied.) Thus if
rombergabs is 0.0 (the default) you just get the relative error test. The
usefulness of the additional variable comes when you want to perform an
integral, where the dominant contribution comes from a small region. Then you
can do the integral over the small dominant region first, using the relative accuracy
check, followed by the integral over the rest of the region using the absolute
accuracy check.
Example: Suppose you want to compute
|
|
'integrate (exp(-x), x, 0, 50) |
(numerically) with a relative
accuracy of 1 part in 10000000. Define the function. n is a counter, so
we can see how many function evaluations were needed. First of all try doing
the whole integral at once.
|
|
(%i1) f(x) := (mode_declare (n, integer, x, float), n:n+1, exp(-x))$(%i2) translate(f)$Warning-> n is an undefined global variable.(%i3) block ([rombergtol: 1.e-6, romberabs: 0.0], n:0, romberg (f, 0, 50));(%o3) 1.000000000488271(%i4) n;(%o4) 257 |
That approach required 257 function
evaluations. Now do the integral intelligently, by first doing 'integrate (exp(-x), x, 0, 10) and then setting rombergabs to 1.E-6 times (this partial integral). This approach takes only 130
function evaluations.
|
|
(%i5) block ([rombergtol: 1.e-6, rombergabs:0.0, sum:0.0], n: 0, sum: romberg (f, 0, 10), rombergabs: sum*rombergtol, rombergtol:0.0, sum + romberg (f, 10, 50));(%o5) 1.000000001234793(%i6) n;(%o6) 130 |
So if f(x) were a function that
took a long time to compute, the second method would be about 2 times quicker.
Default value: 11
The accuracy of the romberg
integration command is governed by the global variables rombergtol and rombergit. romberg will
return a result if the relative difference in successive approximations is less
than rombergtol. It will try halving the stepsize rombergit times before it
gives up.
Default value: 0
rombergmin governs the minimum number of function evaluations that romberg will make.
romberg will evaluate its first arg. at least 2^(rombergmin+2)+1 times.
This is useful for integrating oscillatory functions, when the normal converge
test might sometimes wrongly pass.
Default value: 1e-4
The accuracy of the romberg
integration command is governed by the global variables rombergtol and rombergit. romberg will
return a result if the relative difference in successive approximations is less
than rombergtol. It will try halving the stepsize rombergit times before it
gives up.
Function: tldefint (expr, x, a, b)
Equivalent to ldefint with tlimswitch set to true.