-- Special operator: do The
do statement is used for performing iteration. Due to its great generality the
do statement will be described in two parts. First the usual form will be given which is analogous to that used in several other programming languages (Fortran, Algol, PL/I, etc.); then the other features will be mentioned.
There are three variants of this form that differ only in their terminating conditions. They are:
for <variable>: <initial_value> step <increment> thru <limit> do <body>
for <variable>: <initial_value> step <increment> while <condition> do <body>
for <variable>: <initial_value> step <increment> unless <condition> do <body>
step may be given after the termination condition or limit.)
<initial_value>, <increment>, <limit>, and <body> can be any expressions. If the increment is 1 then "
step 1" may be omitted.
The execution of the
do statement proceeds by first assigning the <initial_value> to the <variable> (henceforth called the control-variable). Then: (1) If the control-variable has exceeded the limit of a
thru specification, or if the condition of the
true, or if the condition of the
false then the
do terminates. (2) The <body> is evaluated. (3) The increment is added to the control-variable. The process from (1) to (3) is performed repeatedly until the termination condition is satisfied. One may also give several termination conditions in which case the
do terminates when any of them is satisfied.
In general the
thru test is satisfied when the control-variable is greater than the <limit> if the <increment> was non-negative, or when the control-variable is less than the <limit> if the <increment> was negative. The <increment> and <limit> may be non-numeric expressions as long as this inequality can be determined. However, unless the <increment> is syntactically negative (e.g. is a negative number) at the time the
do statement is input, Maxima assumes it will be positive when the
do is executed. If it is not positive, then the
do may not terminate properly.
Note that the <limit>, <increment>, and termination condition are evaluated each time through the loop. Thus if any of these involve much computation, and yield a result that does not change during all the executions of the <body>, then it is more efficient to set a variable to their value prior to the
do and use this variable in the
The value normally returned by a
do statement is the atom
done. However, the function
return may be used inside the <body> to exit the
do prematurely and give it any desired value. Note however that a
return within a
do that occurs in a
block will exit only the
do and not the
block. Note also that the
go function may not be used to exit from a
do into a surrounding
The control-variable is always local to the
do and thus any variable may be used without affecting the value of a variable with the same name outside of the
do. The control-variable is unbound after the
(%i1) for a:-3 thru 26 step 7 do display(a)$ a = - 3
a = 4
a = 11
a = 18
a = 25
(%i1) s: 0$ (%i2) for i: 1 while i <= 10 do s: s+i; (%o2) done (%i3) s; (%o3) 55
Note that the condition
while i <= 10 is equivalent to
unless i > 10 and also
(%i1) series: 1$ (%i2) term: exp (sin (x))$ (%i3) for p: 1 unless p > 7 do (term: diff (term, x)/p, series: series + subst (x=0, term)*x^p)$ (%i4) series; 7 6 5 4 2 x x x x x (%o4) -- - --- - -- - -- + -- + x + 1 90 240 15 8 2
which gives 8 terms of the Taylor series for
(%i1) poly: 0$ (%i2) for i: 1 thru 5 do for j: i step -1 thru 1 do poly: poly + i*x^j$ (%i3) poly; 5 4 3 2 (%o3) 5 x + 9 x + 12 x + 14 x + 15 x (%i4) guess: -3.0$ (%i5) for i: 1 thru 10 do (guess: subst (guess, x, 0.5*(x + 10/x)), if abs (guess^2 - 10) < 0.00005 then return (guess)); (%o5) - 3.162280701754386
This example computes the negative square root of 10 using the Newton- Raphson iteration a maximum of 10 times. Had the convergence criterion not been met the value returned would have been
Instead of always adding a quantity to the control-variable one may sometimes wish to change it in some other way for each iteration. In this case one may use
next <expression> instead of
step <increment>. This will cause the control-variable to be set to the result of evaluating <expression> each time through the loop.
(%i6) for count: 2 next 3*count thru 20 do display (count)$ count = 2
count = 6
count = 18
As an alternative to
for <variable>: <value> ...do... the syntax
for <variable> from <value> ...do... may be used. This permits the
from <value> to be placed after the
next value or after the termination condition. If
from <value> is omitted then 1 is used as the initial value.
Sometimes one may be interested in performing an iteration where the control-variable is never actually used. It is thus permissible to give only the termination conditions omitting the initialization and updating information as in the following example to compute the square-root of 5 using a poor initial guess.
(%i1) x: 1000$ (%i2) thru 20 do x: 0.5*(x + 5.0/x)$ (%i3) x; (%o3) 2.23606797749979 (%i4) sqrt(5), numer; (%o4) 2.23606797749979
If it is desired one may even omit the termination conditions entirely and just give
do <body> which will continue to evaluate the <body> indefinitely. In this case the function
return should be used to terminate execution of the
(%i1) newton (f, x):= ([y, df, dfx], df: diff (f (x), x), do (y: ev(df), x: x - f(x)/y, if abs (f (x)) < 5e-6 then return (x)))$ (%i2) sqr (x) := x^2 - 5.0$ (%i3) newton (sqr, 1000); (%o3) 2.236068027062195
return, when executed, causes the current value of
x to be returned as the value of the
block is exited and this value of the
do is returned as the value of the
block because the
do is the last statement in the block.)
One other form of the
do is available in Maxima. The syntax is:
for <variable> in <list> <end_tests> do <body>
The elements of <list> are any expressions which will successively be assigned to the
variable on each iteration of the <body>. The optional termination tests <end_tests> can be used to terminate execution of the
do; otherwise it will terminate when the <list> is exhausted or when a
return is executed in the <body>. (In fact,
list may be any non-atomic expression, and successive parts are taken.)
(%i1) for f in [log, rho, atan] do ldisp(f(1))$ (%t1) 0 (%t2) rho(1) %pi (%t3) --- 4 (%i4) ev(%t3,numer); (%o4) 0.78539816
There are also some inexact matches for
?? do to see them.
(%o1) true (%i2)
:lisp (defun split-if...
:lisp (split-if #'odd...
:lisp (split-if (lamb...