Página de Maxima
Controle de fluxo no Maxima
Autor: Sadao Massago
instituição: DM-UFSCar
web: http://www.dm.ufscar.br/~sadao
data: 2017-12-25
site do maxima e manual
http://maxima.sourceforge.net/
http://maxima.sourceforge.net/documentation.html
Um dos manuais mais recomendado é
http://maxima.sourceforge.net/docs/manual/en/maxima.html
A versão em PDF em
http://maxima.sourceforge.net/docs/manual/en/maxima.pdf
A versão em português (um pouco desatualizado) em
http://maxima.sourceforge.net/docs/manual/pt/maxima.html
Para executar
<cntrl><ENTER> executa o bloco de comando onde o cursor esta
<ctrl>R executa todo arquivo
Para acrescentar códigos e comentários
F5 abre o campo de comando
F6 abre o campo de comentario (texto)
Estes e outros comandos estão no menu "cell".
F1 abre a ajuda do Maxima. Se o cursor estiver sobre a palavra,
procurara por esta paravra na ajuda.
Assume que já leu o "part01_intro.wxm" ("Introdução ao Maxima")
| (%i1) |
/* limpando a memoria */ kill(all); reset(); |
1 Execussão condicional if/then/else
A condicional
if condição then comando 1 else comando2
executa o comando1 quando a condição for verdadeira e comando2 quando e falsa.
Também pode ser usado sem o else como em
if condição then comando
que executara o comando só se condição for verdadeira.
| (%i3) |
y : if(x<0) then 1+x else 1-x; wxplot2d(y, [x, -1, 1]); |
\[\mathrm{\tt (\%o3) }\quad \]
O comando pode ser uma única expressão ou sequência de expressões ou comandos delimitado pelos parênteses e separado pela virgula. Neste caso, o valor retornado é da última expressão. Note que nao é ponto e virgula ou dolar que separam os comandos, o que requer cuidados.
No exemplo a seguir, verifica se e linear ou quadrática e retorna soluções da equação.
| (%i7) |
a : 2; b : 1; c : 4; if a = 0 and b = 0 then ( print("ERRO: a = 0 e b = 0"), 0 ) else if a = 0 then -c/b else [(-b + sqrt(b^2-4*a*c))/(2*a), (-b + sqrt(b^2-4*a*c))/(2*a)]; |
print() é uma função que imprime os valores. A menssangem é um valor literário que no maxima, será delimitado pelas aspas.
| (%i9) |
absoluto(x) := if x < 0 then -x else x; absoluto(-3); |
O if/then/else
Pode assumir a forma
if condição_1 then comando_1
else if condição_2 then comando_2
else if condição_3 then comando_3
...
else comando_n
Isto permite definir unção definidos por partes
| (%i11) |
f(x) := if x < -1 then 0 else if x < 0 then x+1 else if x < 1 then 1-x else 0; wxplot2d(f(x), [x, -2, 2])$ |
2 Laço de contagem for
Para efetuar a contagem, usamos a forma for ind : inicio thru final step passo do comando
| (%i12) | for i : 1 thru 10 step 2 do print("i = ", i); |
Quando passo é 1, podemos omitir o step e ficar como for indice : inicio thru final do comando.
| (%i13) | for i : 1 thru 5 do print("i = ", i); |
Usando isso, vamos calcular o fatorial de um número dado.
| (%i18) |
n : 5; p : 1$ for i:2 thru n do p : p*i$ /* valor calculado */ p; /* valor de maxima */ n!; |
No caso do laco de contagem, indice do laço existirá somente dentro do laco por padrão. Assim, não interfere no valor de fora do laço.
| (%i21) |
i : -1; for i:1 thru 5 do print("i=", i); i; |
3 Laço de repetição while/do
while condição do comando execua o comando até que a condição seja falsa. Atente ao fato de que, se a condição nunca for satisfeita, ele entrará em loop infinito, o que requer cuidados
| (%i26) |
n : 5; p : n$ k : n$ while k>1 do ( k : k-1, p : p * k )$ p; |
4 Laço de repetição do/while
Não existe o laço explícito do "do/while" no maxima,
mas pode ser simulado facilmente pelo comando do.
do comando
efetua o comando indefinidamente.
Colocando o "if condição then return (valor)", poderá parar o laço.
O do/while (condição) é quando "if not condição then return (valor)"
se encontra no final do laço.
Não esqueça de colocar o valor de retorno no return para evitar que
laço continue indefinidamente.
| (%i31) |
n : 20; p : n$ k : n$ do ( k : k-1, p : p * k, if k<=1 then return (p) )$ p; |
5 Combinando ou abreviando os comandos de laços
Laço no maxima podem ser combinados, algumas coisas omitidas, etc Combinação de laços é uma das mais estruturas de repetição mais versáteis no maxima. Por exemplo, se apenas efetuar n vezes for importante, nem recisa usar o contador
| (%i32) | thru 5 do print("Alo!"); |
Quando inicio é 1, podemos omitir o " : 1" e colocar somente for indice thru final do comando
| (%i33) | for i thru 5 do print("i = ", i); |
Incremento não convencional. No for, assume que incrementa um valor fixo a cada iteração, mas pode querer que o valor novo não seja adicinar um constante. Por exemplo, o indice pode dobrar a cada passo. Neste caso, usa-se o next em vez do step para indicar qual será o novo valor de contador
| (%i34) | for k:1 next 2*k thru 10 do print("k= ", k)$ |
Em vez de variavel : valor inicial no for, podera usar variavel from valor inicial o step ou next também pode preceder o thru.
| (%i35) | for k from 1 step 2 thru 10 do print("k= ", k)$ |
Se precisar acrescentar condição adicional no laço de contagem, basta combinar com o while
| (%i37) |
l : [1, 2, 3, 5, 0, 2]; for i:1 thru length(l) while l[i] > 0 do print("l[",i,"]= ", l[i]); |
for incrementa o contador. Combinando com o while,
poderá fazer parar com outras condições que
não é necessariamente o estouro de interacao.
Seguinte código é equivalente ao exemplo anterior.
| (%i39) |
l : [1, 2, 3, 5, 0, 2]; for i:1 while l[i] > 0 and i<length(l) do print("l[",i,"]= ", l[i]); |
Outra forma de for e executar para cada membro da lista
for item in lista do comando
Por exemplo, poderá listar valores das funções da lista na variável.
apply aplica a função em cada elemento da lista do segundo parámetro.
Não foi usado f(x), pois f já está sendo usado neste arquivo
(no começo do arquivo) e maxima
optará em calcular f(x) para este f pre-definido em vez do f
do laço.
| (%i41) |
/* kill(f); */ x : 1; for f in [exp, log, rho, atan] do print("f(", x, ")= ", apply(f, [x] ) )$ |
6 Retornando do laço
O laço é interrompido pelo comando return (valor). No entanto, return sai do último laço (e não de todos laços)
| (%i45) |
l : [1,2,3,4,-3,4]; /* checar se todos elementos são positivos */ flag : true; for x in l do if x <= 0 then ( flag : false, return (false) ); flag; |
O return (valor) retorna do ultimo laço.
Caso nao estiver dentro do laço, retorna do
bloco de códigos.
Por exemplo, seguinte código não funciona como
exemplo anterior, pois ao sair do laco,
volta no bloco de expressao e continuará executando
o código. Como a última expressao é true,
sempre retornará true.
| (%i48) |
l : [1,2,3,4,-3,4]; /* checar se todos elementos são positivos */ flag : (for x in l do if x <= 0 then return (false), true ); flag; |
Este tipo de erro e comum para quem já conhece outras linguagens de programacao como C/C++ na qual return retornará da função, mas o return do maxima é como o break de C/C++ que apenas interrompe o laço. So retornara da função, caso não estiver dentro do laço.
Se quer sair de város laços de uma vez, deverá usar o throw/catch
| (%i50) |
M : matrix([1,2],[-1,3]); /* chcar se todas entradas são positivas */ catch( for i:1 thru length(M) do for j:1 thru length(M[1]) do if M[i,j] <= 0 then throw (false), true ); |
throw gera uma excessão e faz sair de todos laços/funções até encontrar catch.
7 Outras formas de laços menos usados
Em vez de while, poderá usar o unless que é até que. No while, o laço continua enquanto condição for verdadeira, mas no unless, o laço é interronpido quando a condição for verdadeira (while e unless são opostas)
| (%i52) |
l : [1, 2, 3, 5, 0, 2]; for i:1 unless l[i] <=0 or i>length(l) do print("l[",i,"]= ", l[i]); |
| (%i54) |
i : 1; unless i > 10 do ( print("i= ", i), i : i+1 ); |
go é um comando equivalente a goto de C/C++ e serve para pular de
um lugar para posicao anterior dentro do bloco de comando
delimitado pelo block.
Em geral, boa pratica de programação recomenda não usar o
goto (go do maxima) para deixar código mais fácil de ser analisado.
Portanto, se precisar de go,
pense antes se não pode ser substituido pelo outro laço.
A seguir, uso de go para simular o laço for
| (%i56) |
l : [1, 2, 3, 5, 0, 2]; block([], i : 1, inicio, print("l[",i,"]= ", l[i]), i: i+1, if i<length(l) then go (inicio) )$ |
O comando block() permite delimitar o código de maxima
para definir variaveis locais.
Note que o primeiro parametro do block foi deixado como
lista vazia por não ter variaveis locais neste código.
Para que go funcione, precisa estar delimitado pelo block.
O uso de block é especialmente importante para definir funções.
8 Definindo a variável local com o uso de block()
Quando estamos escrevendo códigos longos, algunas variáveis começam a ser usados.
As vezes, queremos usar a mesma variável sem perder o valor já existente,
ou em outras palavras, queremos restaurar o valor após o uso.
Para tanto, usa-se o comando block que delimita os comandos como em parenteses,
mas o primeiro argumento é uma lista contendo variáveis locais.
Os valores das variaveis locais serão salvos antes de entrar no block e é restaurado
depois de sair do block
O valor retornado pelo block() é da ultima expressao.
Se quer exibir o valor intermediário,
use display()/disp(), print(), etc.
| (%i59) |
x : 1; /* o uso de variavel local para garantir que x seja símbolo, sem o uso de aspas, mesmo já tendo armazenado valores */ block([x], wxplot2d(x^2, [x,-1,1]) ); x; |
\[\mathrm{\tt (\%o58) }\quad \]\[\mathrm{\tt (\%o59) }\quad 1\]
Aqui, a é local e pode receber valores, sem mudar o valor fora dela
| (%i64) |
a : 0; y : x^2+x+1; block([a], a : 2, z : a * y )$ z; a; |
Mudando o valor da variável global somente em um trecho
| (%i67) |
fpprec; block([fpprec : 32], disp(fpprec), disp(bfloat(%pi)) ); fpprec; |