h1

PRASLAN: Biblioteca evaluadora de expresiones matemáticas

2 \02UTC julio \02UTC 2008

He sacado algo en limpio de la asignatura de EDI. Vale que me he pasado el curso rascándome los huevos, y que Pascal es la aberración sintáctica hecha estándar, pero los algoritmos son los algoritmos, y ciertamente, los mecanismos para transformar expresiones de notación infija a postfija, y de postfija a árbol de expresión son realmente útiles.

Además, yo gusto de programar muchas mini-recetas de simulación matemática, donde a veces los parámetros no se pueden reducir a un simple conjunto de variables, si no a una expresión algebraica entera. Por eso mismo, tan pronto acabé el curso comencé a escribir el código de esta biblioteca, PRASLAN.

PRASLAN es el nombre de un antiguo proyecto mío de lenguaje de programación interpretado que fracasó, y en cuya carpeta decidí escribir el código. No recuerdo bien lo que significaba el acrónimo por aquel entonces, así que supongo que tengo inventármelo. ¿PRactical Arithmetic Synthesis LANguage, quizá? (Lenguaje práctico de síntesis aritmética) No sé, espero encontrarme un buen significado a lo largo del verano. Ahora mismo es una biblioteca encargada de evaluar expresiones matemáticas de una manera más o menos eficiente y sencilla, pensada para cálculos muy recurrentes.

El caso es que lo hice lo suficientemente sencillo como para que cualquier idiota con unos mínimos conocimientos de C pudiese usarlo. La biblioteca ofrece tan sólo tres funciones (y no tiene por qué ofrecer más) que explicaré ahora:

expr_t *praslan_new (char *expr, int num_variables, ...)
Esta función se encarga de compilar una expresión y de sustituir las variables que se le pidan. Estas variables han de ser complejas (tipo complex incluido en complex.h) y han de especificarse pasándolas como parámetros, dando primero el nombre de la variable como cadena y luego su dirección. Por ejemplo, en el caso que queramos pasar dos variables (i y pi, por ejemplo):

expr_t *expr;
complex i, pi;
i = csqrt (-1); /* Unidad imaginaria. */
pi = 4.0 * catan (1.0); /* Valor de pi */
expr = praslan_new ("exp (i * pi)", 2, "i", &i, "pi", &pi); /* Dos variables */

La función devolverá NULL si la expresión es incorrecta, o un puntero a expr_t con la expresión compilada, lista para ser evaluada.

Ojo: La expresión está compilada, y no evaluada. La evolución se hace a través de otra función que comentaré ahora:

complex praslan_eval (expr_t *expr)
Una vez compilada la expresión, tenemos que evaluarla. Llamando a praslan_eval con el puntero a la expresión previamente obtenida con praslan_new, obtenemos un valor complejo con el resultado. Nótese que es eso, un valor complejo. Si queremos obtener la parte real o imaginaria como un valor tipo double, necesitaremos las funciones creal o cimag (incluidas en complex.h) para extraerlos.

Ojo: Cualquier cambio en los valores de las variables se verá reflejado en las siguientes llamadas a praslan_eval. Por ejemplo, si tenemos:

expr_t *expr;
complex z, resultado;
z = 2.0;
expr = praslan_new ("z^2", 1, "z", &z); /* Una variable */
if (expr == NULL)
{
  fprintf (stderr, "error: expresión mal formada.\n");
  exit(1);
}
resultado = praslan_eval (expr); /* Ahora resultado valdrá 2.0^2 = 4.0 */
z = 3.0;
resultado = praslan_eval (expr); /* Ahora resultado valdrá 3.0^2 = 9.0 */

Esto se debe a que la expresión trabaja en términos de referencias y no de valores. Con esto hacemos el trabajo del cálculo más escalable, y evitamos recompilar una expresión cada vez que queramos evaluarla.

Y la última:

void praslan_free (expr_t *)
Que como podemos suponer, se encarga de liberar el espacio ocupado por una expresión que ya no usamos más.

Para usarla, tenemos que descargarla (enlace de descarga aquí), y compilarla. La compilación es muy sencilla, entramos en la carpeta del código y ejecutamos:

make

Una vez compilador, ejecutamos (como root):

make install

Para escribir programas que hagan uso de esta biblioteca tendremos que asegurarnos de que llevan incluida la cabecera praslan/praslan.h:

#include <praslan/praslan.h>

Y a la hora de compilar, que llevan incluida la biblioteca praslan:

gcc miprograma.c -o miprograma -lpraslan

Qué decir, es un programa nuevo, seguro que tiene muchos bugs, blablabla, pero bueno, espero que alguien me los comente si los encuentra para poder arreglarlos. De momento lo he usado para dibujar fractales y bueno, parece funcionar más o menos bien.

Ah, se me olvidaba: Hay un cacho que tuve que escribir en ensamblador de x86 (de 32 bits) para que fuese más o menos eficiente. Espero poder hacerlo más portable, quitando todos esos __asm__ tan feotes. Pero si queremos compilarlo en otras arquitecturas, lo vamos a tener relativamente jodido. Bueno, en los procesadores de 64 bits hay un wrapper extraño que permite rular bibliotecas de 32 bits. No sé exactamente como se llama, pero sé que se usa mucho (al menos en esta época) a la hora de hacer funcionar el plugin de flash en sistemas de 64 bits.

Edito 6/07/2008: Le he quitado ese asqueroso cacho en ensamblador que no valía para nada. Ahora es menos engorroso y más comprensible (y espero que rápido). Las llamadas se hacen directamente como en el caso de los operadores.

Edito 20/07/2008: He añadido funciones hiperbólicas (aunque son redundantes y se podrían obtener directamente desde sus correspondientes trigonométricas), la función fibo (término general de la sucesión de Fibonacci) y las funciones gamma y beta suciamente copiadas de la biblioteca libcephes. He arreglado un bug que había con funciones de varios parámetros, que hacían que la compilación entrase en un bucle infinito.

Añado de paso una lista de las funciones soportadas por la biblioteca:

pow (base, exp) – Potencia. Lo mismo que base^exp
sqrt (rad) – Raíz cuadrada. Lo mismo que elevar a 0.5
sin (tetha) – Seno del ángulo tetha
cos (tetha) – Coseno del ángulo tetha
tan (tetha) – Tangente del ángulo tetha
atan (val) – Arcotangente del valor val
exp (val) – Exponencial de val (e^val)
log (val) – Logaritmo neperiano de val
re (z) – Parte real del número z
im (z) – Parte imaginaria del número z
abs (z) – Valor absoluto del número z
cosh (val) – Coseno hiperbólico de val
sinh (val) – Seno hiperbólico de val
tanh (val) – Tangente hiperbólico de val
atanh (val) – Arcotangente hiperbólico de val
gamma (z) – Función gamma de z
beta (p, q) – Función beta de p y q
fibo (n) – Término general de la sucesión de Fibonacci
norma (x, y) – Calcula la distancia del punto (x, y) al origen de coordenadas.

Saludos

2 comentarios

  1. Curioso… mmm tendré que mirarlo con mas tiempo en otro momento, pero me parece que ocupas bien tu tiempo xDD


  2. […] libegraph, la cual todavía no he liberado por ser una casa de putas) que originalmente usaba praslan para poder dibujar funciones de dos dimensiones elevándolas en una tercera dimensión. El caso es […]



Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: