Símbolos, funciones y asignaciones,
globales y locales
Constantes y símbolos usuales
- el número e, base de los logaritmos neperianos, representado como %e;
- el número pi, representado como %pi
- la unidad imaginaria del cuerpo de los complejos, representada mediante %i
- la constante de Euler representada como %gamma
- + infinito representada como inf
- - infinito representada como minf
- la razón aúrea ((sqrt(5)+1)/2) representada como %phi
Funciones conocidas
- abs (exp) valor absoluto o módulo
- entier (x) parte entera de x, que se define como el mayor de los enteros que no supera el valor x. Los comandos fix y floor hacen lo mismo.
- round (x) redondeo de x al entero más cercano
- n! factorial de n
- factor(n) descomposición en factores primos de n
- divisor(n) proporciona los divisores de n
- quotien(n,m) resto de la división entera entre n y m
- remainder(n,m) cociente de la división entre n y m
- primep(n) nos dice si n es primo o no
- exp (x) función exponencial de x
- log (x) logaritmo neperiano de x
- max (x1, x2, ...), min (x1, x2, ...) máximo y mínimo
- sign (exp) trata de determinar el signo de una expresión. Devuelve una de las
respuestas siguientes: pos (positivo), neg (negativo), zero, pz (positivo
o cero), nz (negativo o cero), pn (positivo o negativo), o pnz (positivo,
negativo, o cero, i.e. no se sabe).
- realpart(z) parte real de z
- imagpart(z) parte imaginaria de z
- conjugate(z) el conjugado de z
- rectform(z) expresión binomial de z
- polarform(z) expresión en forma polar de z
- sqrt (x) raíz cuadrada de x. Se representa internamente mediante x^(1/2)
- acos(x) arco coseno de x
- acosh(x) arco coseno hiperbólico de x
- acot(x) arco cotangente de x
- acoth(x) arco cotangente hiperbólico de x
- acsc(x) arco cosecante de x
- acsch(x) arco cosecante hiperbólico de x
- asec(x) arco secante de x
- asech(x) arco secante hiperbólico de x
- asin(x) arco seno de x
- asinh(x) arco seno hiperbólico de x
- atan(x) arco tangente de x
- atan2(y,x) proporciona el valor de atan(y/x) en el intervalo -%pi to %pi
- atanh(x) arco tangente hiperbólico de x
- cos(x) coseno de x
- cosh(x) coseno hiperbólico de x
- cot(x) cotangente de x
- coth(x) cotangente hiperbólica de x
- csc(x) cosecante de x
- csch(x) cosecante hiperbólica de x
- sec(x) secante de x
- sech(x) secante hiperbólica de x
- sin(x) seno de x
- sinh(x) seno hiperbólico de x
- tan(x) tangente de x
- tanh(x) tangente hiperbólica de x
- gamma(x) gamma de x
- beta(x,y) beta de x, y
- erf(x) función de error de Gauss
- isqrt(x) parte entera de la raiz cuadrada de x, que debe ser entero
- random(N) donde si N es un número natural genera un pseudoaleatorio natural entre 0 y N-1. Cuando N es un decimal genera un pseudoaleatorio decimal entre 0 y N
- lambda es también una función que resulta muy útil en ocasiones. En la sección de listas puede ver un ejemplo de utilización, y también puede ver ejemplos en la consola ejecutando ? lambda;
- binomial(n,m) número combinatorio n sobre m
- combination(n,m) número de combinaciones de n elementos tomando n de ellos
- permutation(n,m) número de permutaciones de n elementos tomando n de ellos. Estos dos últimos requieren cargar previamente una librería mediante
'load(functs)'
- sqrt(3),numer; devuelve 1.732050807568877
- entier(sqrt(3)); devuelve 1
- entier(-sqrt(3)); devuelve -2
- round(sqrt(3)); devuelve 2
- abs(1+%i); devuelve sqrt(2)
- abs(entier(-sqrt(3))); devuelve 2
- random(6); puede producir cualquier entero entre 0 y 6
- random(10.0); puede producir cualquier número decimal entre 0 y 10
- sqrt(x^2); devuelve abs(x)
- factor(120);
- divisors(120);
- polarform(1/2+\sqrt(3)/2*%i);
- rectform(%e^(%pi*%i/3));
Conviene aclarar que el comando random genera números pseudoaleatorios, en el sentido de que generada una serie de aleatorios, si reiniciamos Maxima y los volvemos a generarla, obtenemos la misma serie.
Para evitar que tal cosa ocurra podemos hacer uso de los comandos
-
make_random_state(true)$
set_random_state(%);
que cambian la "semilla inicial" que se utiliza para generar los pseudoaleatorios (de forma ordenada y preestablecida).
Polinomios
Maxima puede realizar divisiones polinomiales, hacer máximo común divisor y mínimo común múltiplo de polinomios, entre otras operaciones.
- gcd(Polinomio_1,Polinomio_2,...,Variable_1,Variable_2,...,Variable_n)
calcula el máximo común divisor de Polinomio_1,Polinomio_2,...
Existen varios posibles algoritmos para realizar esta operación que pueden
ser declarados como un argumento opcional.
- lcm(Polinomio_1,Polinomio_2,...)
calcula el mínimo común múltiplo de Polinomio_1,Polinomio_2,...
Para poder tener acceso a este comando es necesario cargar el paquete adicional
load(functs) lo cual se consigue con el comando load(functs)
- divide (Polinomio_1, Polinomio_2, Variable_1,...,
Variable_n)
realiza la división entera de Polinomio_1 entre Polinomio_2
siendo Variable_n la variable principal. El resultado es una lista
cuyo primer elemento es el cociente y el segundo el resto.
-
gcd( (x+1)*(x-1)^2*(x^2+1), x^2+2*x+1);
- /* Atención requiere primero load(functs); */
lcm( (x+1)*(x-1)^2*(x^2+1), x^2+2*x+1 );
- divide( x^4-x^3+7*x^2-1, x^2+2*x+1, x );
Otro comando que puede ser útil para eliminar variables en un sistema de ecuaciones es
- eliminate ([eq1,eq2,...,eqn],[v1,v2,...,vk])
donde eq1,eq2... son ecuaciones (o expesiones que se suponen igualadas a cero) y v1,v2... son variables que se tratan de eliminar utilizando las ecuaciones anteriores
block(
exp1: 2*x^2 + y*x + z,
exp2: 3*x + 5*y - z - 1,
exp3: z^2 + x - y^2 + 5,
eliminate ([exp3, exp2, exp1], [y, z])
);
Asignar de valores. Definir nuevas funciones
Con frecuencia es necesario reutilizar en otro lugar el resultado de un cálculo ya realizado. Pero más eficiente que las operaciones de copiar/pegar resulta el hacer uso de la posibilidad que Maxima ofrece de asignar un Nombre
a ese resultado y poderlo llamar del mismo en cualquier otro lugar.
Otro tanto ocurre con la utilización de funciones construidas en base a las que Maxima conoce: igualmente resulta de utilidad asignarles un Nombre
y poder utilizarla sin necesidad de volver a escribir la fórmula. Describimos a continuación los comandos que gestionan esas tareas.
- Nombre : Valor
Valor puede ser un número, una expresión simbólica (fórmula).
- NombreFunción(x1,x2,...xn) := expresión
Es la forma más sencilla de definir una nueva función a través de funciones ya conocidas.
- define(NombreFunción(x1,x2,...xn), expresión)
Es otra manera de definir una nueva función. Cuando se define una función usando
la forma :=, no se evalúa la expresión que sirve para definirla. En cambio, cuando se usa este comando sí se evalúa la expresión
- alias(NombreNuevo1,NombreOriginal1,NombreNuevo2,NombreOriginal2,...)
En caso de conveniencia es posible referirse a una función que Maxima conozca utilizando para ello un NombreNuevo que es declarado con este comando.
Vamos a ilustrar con algunos ejemplos el funcionamiento y las diferencias entre las diferentes formas de definir una función
- a: 2$ b:3$ a*b;
- /* anulamos el valor asignado */ kill(a)$ F1(x):=a*x^2+1;
- /* derivamos la función */
diff(F1(x),x);
- /* asignamos valor al parámetro */
a:2$
- /* calculamos de nuevo la derivada tras la asignación */ diff(F1(x),x);
- F2(x):=x^2+1;
- F2(3);
- /* dibuja F2 en el intervalo [-1,1] */ plot2d(F2(x),[x,-1,1]);
- /* dibuja F3 en los intervalos seƱalados */ F3(x,y):=x^2-y^2; plot3d(F3(x,y),[x,-1,1],[y,-1,1]);
- /* ahora tendremos dos nombres para la misma función */ alias(sen,sin)$
- sen(%pi/2); sin(2*%pi);
En la asignación de valores, como hemos señalado, se utiliza : y no =. El símbolo de igualdad se emplea fundamentalmente con las ecuaciones, si bien también aparece en las operaciones de sustitución y evaluación de expresiones.
Por otra parte, la asignación de valores tiene un ámbito de aplicación más amplio que establecer el valor de una constante en una fórmula, tal y como ha sido utilizado más arriba. Por ejemplo es posible utilizar el comando : para definir una función, (incluso sin declarar explícitamente la variable) como hacemos a continuación. y .
- kill(all)$ F1 : x^2+1;
- F2 : diff(F1,x);
- ev(F2, x=3);
- subst(x=3,F2);
Como ya hemos comentado en otras ocasiones
? : ;
proporciona información sobre otros posibles usos del comando
Otros ejemplos que ilustran la diferencia entre las dos formas de definir una función:
- kill(f,g,h,k)$
- expr : cos(y) - sin(x);
- f(x,y):=expr;
- define(g(x,y),expr);
Desde un punto de vista abstracto parece que las funciones f y g anteriormente definidas coinciden. Sin embargo f y g tienen un comportamiento diferente en Maxima, como muestran los resultados siguientes.
- f(a,b);
devuelve algo diferente de lo que se está esperando.
- g(a,b);
devuelve lo que se espera como resultado.
- h(x,y) := cos(y) - sin(x);
funciona como cabía esperar
h(a,b);
- Un resultado similar puede obtenerse si en la definición de la función se fuerza la evaluación previa, como ocurre con la función k que aparece a continuación
k(x,y):=ev(expr);
y ahora sí se obtiene el resultado esperado
k(a,b);
- Otra manifestación de las diferencias es la siguiente (vea el resultado de la ejecución en la consola)
kill(all)$
f(x):=cos(x);
g(x):=diff(f(x),x);
g(x);
g(0);
La última no funciona.
- Repetimos los cálculos usando ahora el comando define y ahora todo funciona como cabría esperar (vea el resultado de la ejecución en la consola)
kill(all)$
f(x):=cos(x);
define(g(x),diff(f(x),x));
g(x);
g(0);
La clave para interpretar los resultados anteriores está en que define
evalua siempre su segundo argumento, a menos que se indique lo contrario con el operador de comilla simple; por el contrario :=
no hace esa evaluación.
Resumiendo: aunque la sintaxis sea un poco más complicada, utilizar define
es aconsejable aconsejable porque su comportamiento es cercano al que un humano espera. Para más detalles, y variaciones sobre esta cuestión puede ejecutar
? define;
y ver la información proporcionada al respecto en la consola de Maxima.
Conocer o desasignar valores y funciones
Cada función definida, o cada asignación realizada, permanece activa, salvo que se haya realizado con caracter local en un bloque hasta que se desactiva.
- functions
Permite conocer la lista de las funciones definidas por el usuario
- fundef(NombreFunción)
Permite conocer la definición de cada una de las funciones creadas por el usuario
- values
Permite conocer las asignaciones realizadas por el usuario
- kill(all), kill(functions), kill(NombreFunción), kill(Variable)
Permite desactivar definiciones y asignaciones realizadas anteriormente. Son algunos de los usos del comando.
Este comando resulta de utilidad en procedimientos complejos para evitar resultados indeseados. En tales situaciones puede ser conveniente comenzar el procedimiento usando kill(all)
Ejecute el comando
? kill;
para más información y otros usos del mismo.
También posible realizar las definiciones y asignaciones dentro de un bloque, en cuyo caso al salir del bloque se olvidan tales definiciones y asignaciones.
- G:x^2+1$ H:y+1$
- G*H;
- kill(G,H);
- G*H;
Asumir algo y olvidarse de ello después
Cuando Maxima tiene dudas sobre algún dato que puede influir en cual sea su respuesta, antes de darla hace preguntas.
Copie y pegue este texto en la consola y responda a la pregunta formulada, no se olvide de poner el ; al final de su respuesta
integrate(exp(a*x),x,0,inf);
Los siguientes comandos resultan de utilidad porque permite evitar las preguntas dando de antemano las respuestas.
- assume(predicado1,predicado2...)
Como su nombre indica, asume ciertas hipótesis sobre los predicados. Los predicados tan solo pueden ser expresiones formadas con los operadores relacionales menor que <, menor o igual que <=, mayor que >, mayor o igual que >=.
- forget(predicado1,predicado2...)
Anula lo asumido respecto de los predicados indicados.
- facts()
Permite conocer las suposiciones activas en ese momento.
- assume(a<0);
integrate(exp(a*x),x,0,inf);
- facts();
forget(a<0);
assume(a>0);
integrate(exp(a*x),x,0,inf);
forget(a>0);
Si, por ejemplo, el primero lo ejecuta dos veces verá que Maxima le responde que la suposición es redundante, porque obviamente se le dijo anteriormente. Esto significa que Maxima se acuerda de las suposiciones realizadas, que podrían llegar a ser contradictorias. En consecuencia puede ser necesario anular las suposiciones previas antes de realizar una nueva.
Bloques
Las asignaciones se realizan, por defecto, globalmente y afectan a todas las sentencias que se se ejecuten después de la asignación y que tengan que ver con ella. El comando block, entre otras cosas, permite limitar el campo de acción de una asignación a un bloque de código.
block([v_1,...,v_n], expr_1,...,expr_m) o bien
block(expr_1,...,expr_m)
El efecto del comando es evaluar las expresiones secuencialmente y devolver el valor de la última expresión evaluada.
En caso de usarse, las variables v_1,...,v_n son locales en el bloque y se distinguen de las globales que tengan el mismo nombre. Si no se declaran variables locales entonces se puede omitir la lista. Dentro del bloque, cualquier otra variable distinta de v_1,...,v_n se considera global. Al iniciarse, block guarda los valores actuales de las variables v_1,...,v_n y los recupera al finalizar, olvidando en cambio los valores que con carácter local dentro del bloque hayan tenido éstas.
Los comandos block pueden anidarse. Las variables locales se inicializan cada vez que se entra dentro de un nuevo
bloque. Las variables locales de un bloque se consideran globales dentro de otro anidado dentro del primero. Si una variable es no local dentro de un bloque, su valor es el que le corresponde en el bloque superior. Este criterio se conoce con el nombre de "alcance dinámico". El valor del bloque es el de la última sentencia o el argumento de la función return, que puede utilizarse para salir del bloque.
Lea el manual para más información:
? block;
Una primera ilustración del uso del comando:
- x:5$ y:6$ x*y;
- block([x,y],x:9, y:3, x*y);
- x*y;
En el ejemplo que sigue, creado por J. Rafael Rodríguez Galván, se realiza una utilización más elaborada del comando block para obtener los ceros aproximados de una función que cambia de signo en un intervalo. Aparecen en él otros comandos como condicionales y similares propios de programación más avanzada. El lector que conozca el método de bipartición será capaz de comprender la estructura del código.
- /* creación del comando biparticion */
biparticion(f_objetivo,a,b,epsilon) :=
block(
if( sign(f_objetivo(a)) = sign(f_objetivo(b)) )
then ( print("ERROR, f tiene el mismo signo en a y en b"), return(false) )
else do ( c:(a+b)/2,
if( abs(f_objetivo(c))<epsilon)
then return(c),
if( sign(f_objetivo(a)) = sign(f_objetivo(c)) )
then a:c else b:c
)
)$
- /* cero de una función en un intervalo usando biparticion */
f(x):=(2*x)^2-exp(-x)$
biparticion(f,0,1,0.01), numer;
Funciones definidas a trozos: uso de condicionales
Maxima permite construcciones del tipo siguiente:
-
if condición then expresión1 else expresión2
-
if condición1 then expresión1 elseif condición2 then expresión2 else expresión3
La condición debe ser evaluable como true o false y las expresión1, expresion2 son expresiones válidas de Maxima, incluidas expresiones if
anidadas. Si la condición es cierta entonces se ejecuta expresion1 y en otro caso se ejecuta expresión2
Las condiciones frecuentemente utilizan alguno de los siguientes operadores relacionales
= ... igual a ...
< ... menor que ...
<= ... menor o igual que ...
> ... mayor que ...
>= ... mayor o igual que ...
# ... distinto de ...
es posible utilizar más de un condicional utilizando and
- F(x):=if x<0 then 0 else x^2;
- plot2d( F(x), [x,-1,1], [y,-1,1] )$
Un ejemplo de anidamiento de condicionales
- kill(all)$
F(x):=if x<0 then 0 else (if x<1 then x^2 else 1) ;
- plot2d( F(x), [x,-1,2], [y,-1,2] );
Una construcción diferente con idéntico resultado
- kill(all)$
F(x):=if (x<0) then 0 elseif (x>0 and x<1) then x^2 else 1;
- plot2d( F(x), [x,-1,2], [y,-1,2] );
Ap_Funciones.wxmx
Ap_Random.wxmx Los números "aleatorios"
son realmente pseudoaleatorios.