Section: User Commands (1)
Updated: .
Index Return to Main
Contents
bc - Un lenguaje de cálculo de precisión arbitraria
[ -lwsqv ] [opciones largas] [ fichero ... ]
Esta página de manual documenta la versión 1.04 de GNU bc.
es un lenguaje que permite la ejecución interactiva de sentencias con precisión numérica arbitraria. La sintaxis es similar a la del lenguaje de programación C. Se puede disponer de una biblioteca matemática estándar a través de una opción en la línea de comando. En ese caso, la biblioteca matemática se determina antes de procesar ningún fichero. bc comienza procesando en orden todos los ficheros dados en la línea de comando. Después de que todos los ficheros hayan sido procesados, bc lee la entrada estándar. Todo el código es ejecutado tal y como es leído. (Si un fichero contiene un comando que detiene el procesador bc nunca leerá la entrada estándar.)
Esta versión de bc tiene varias ampliaciones adicionales a las tradicionales implementaciones de bc y el estándar POSIX. Las opciones en la línea de comando pueden causar que estas extensiones impriman un aviso o sean rechazadas. Este documento describe el lenguaje aceptado por este procesador. Las ampliaciones serán identificadas como tales.
El elemento más básico en bc es el número. Los números son de precisión arbitraria, tanto en la parte entera como en la fraccionaria. Todos los números son representados internamente en decimal y toda la computación es hecha en decimal. (Esta versión trunca los resultados de las operaciones división y multiplicación). Los números tienen dos atributos, la longitud y la escala. La longitud es el número total de dígitos decimales significativas y la escala el número de dígitos decimales tras la coma decimal. Por ejemplo:
<dl><dt><dd> .000001 tiene longitud 6 y escala 6. 1935.000 tiene longitud 7 y escala 3. </dl>
Los números son almacenados en dos tipos de variables, variables simples y matrices. Ambos tipos son designados por nombres. Estos nombres comienzan con una letra, seguida por cualquier número de letras, dígitos y caracteres de subrayado. Todas las letras deben ir en minúsculas. (Estos nombres alfanuméricos son una ampliación. En el bc de POSIX todos los nombres son una sola letra minúscula). El tipo de variable queda claro según el contexto ya que a todas las variables de tipo matriz les sigue unos corchetes ([]).
Hay cuatro variables especiales, scale, ibase, obase y last. scale define como son tratadas los dígitos tras la coma decimal en algunas operaciones. El valor por defecto de scale es 0. ibase y obase definen la base numérica de conversión para la entrada y la salida. El valor por defecto para ambos es la base 10. last (una ampliación) es la variable en la que se guardar el último número mostrado. Todo esto será tratado en detalle cuando proceda. Todas estas variables pueden tener un valor asignado así como ser usadas en expresiones.
Los comentarios en bc comienzan con los caracteres /* y finalizan con los caracteres */. Los comentarios pueden empezar en cualquier lugar y aparecen como un solo espacio en la entrada. (Esto hace que delimiten otros elementos de entrada. Por ejemplo, un comentario no puede encontrarse en medio del nombre de una variable). Los comentarios pueden incluir saltos de línea.
Para poder usar macros (scripts) en bc, la posibilidad de incluir comentarios de una sola línea ha sido añadida como ampliación. Estos comienzan con el carácter # y continúan hasta el final de la línea. El final de línea no es parte del comentario y es procesado de forma normal.
Los números son manipulados por las expresiones y las sentencias. Como el lenguaje fue diseñado para ser interactivo, las sentencias y expresiones son ejecutadas tan pronto como es posible. No hay programa principal ("main"). En su lugar, el código es ejecutado tal y como se encuentra. (Las funciones, tratadas en detalle más abajo, se definen cuando se encuentran).
Una constante es la expresión más simple. bc convierte internamente las constantes en números decimales usando la base de entrada activa, especificada por la variable ibase. (Hay una excepción en las funciones). Los valores permitidos para ibase van del 2 hasta el 16. Si se asigna un valor a ibase fuera de este rango se cambiará por 2 ó 16. Los números en la entrada pueden formarse con los caracteres 0-9 y A-F. (Nota: Deben ir en mayúsculas. Las minúsculas son nombres de variables). Los números de un solo dígito tienen siempre el valor del dígito, sea cual sea el valor de ibase. (ej. A = 10.). En los números de más de un dígito bc cambia todos los dígitos mayores o iguales a ibase al valor de ibase-1. Esto hace que el número FFF sea siempre el mayor número de 3 dígitos de la base de entrada.
Las expresiones más complejas son similares a muchos otros lenguajes de alto nivel. Como sólo hay un tipo de número, no hay reglas para mezclar tipos. En cambio, hay reglas para la escala de las expresiones. Cada expresión tiene una escala. Esta es derivada de la escala de los números originales, la operación realizada y, en muchos casos, el valor de la variable scale. Los valores permitidos para scale son desde 0 hasta el máximo número representable por un entero en C.
En las siguientes descripciones de expresiones permitidas, "expr" se usa para indicar un expresión completa y "var" una variable, simple o matricial. Una variable simple es, simplemente
y una matriz se designa así
Si no se especifica la escala del resultado, esta será la máxima escala de las expresiones implicadas.
Las expresiones relacionales son de un tipo especial que siempre se evalúan a 0 ó 1, 0 si la relación es falsa y 1 si la relación es verdadera. Pueden aparecer en cualquier expresión permitida. (El bc de POSIX sólo permite el uso de expresiones relacionales en las sentencias if, while y for y sólo una expresión relacional en cada una de ellas). Los operadores relacionales son:
Las operaciones booleanas también están permitidas. (El bc de POSIX NO tiene operaciones booleanas). El resultado de toda operación booleana es 0 ó 1 (falso o verdadero) como en las expresiones relacionales. Los operadores booleanos son:
La precedencia de las expresiones es la siguiente (de menor a mayor):
<dl><dt><dd>operador || , asociativo por la izquierda operador && , asociativo por la izquierda operador ! , no asociativo operadores relacionales, asociativos por la izquierda operador asignación, asociativo por la derecha operadores + y - , asociativos por la izquierda operadores *, / y % , asociativos por la izquierda operador ^ , asociativo por la derecha operador unario - , no asociativo operadores ++ y -- , no asociativo </dl>
Esta precedencia fue elegida para que los programas acordes con el bc de POSIX funcionaran correctamente. Esto hará que el uso de operadores relacionales y lógicos tenga un comportamiento inusual cuando se usen con expresiones de asignación. Considere la expresión:
La mayoría de los programadores de C asumirían que se asignaría el resultado de "3 < 5" (el valor 1) a la variable "a". Lo que ocurre en bc es que se asigna el valor 3 a la variable "a" y entonces se compara 3 con 5. Es mejor usar paréntesis cuando se usan operadores relacionales y lógicos con operadores de asignación.
Hay algunas expresiones especiales más en bc. Estas están relacionadas con las funciones definidas por el usuario y las funciones estándar. Tienen la forma "nombre(parámetros)". Las funciones definidas por el usuario son tratadas en la sección FUNCIONES. Las funciones estándar son:
Las sentencias (como en la mayoría de los lenguajes algebraicos) proporcionan la secuencia de las evaluación de las expresiones. En bc las sentencias son ejecutadas "tan pronto como es posible". La ejecución ocurre cuando se encuentra un cambio de línea y hay una o más sentencias completas. Debido a esta ejecución inmediata, los cambios de línea son muy importantes en bc. En realidad, tanto el punto y coma como el cambio de línea son usados como separadores de sentencias. Un cambio de línea en un lugar inapropiado provocará un error de sintaxis. Es posible ocultar el que un cambio de línea sea un separador de sentencias usando el carácter de contra-barra. bc toma la secuencia "\<nl>", donde <nl> es el cambio de línea, como un espacio en blanco en lugar de como un cambio de línea. Una lista de sentencias es una serie de sentencias separadas por punto y coma y cambios de línea. Lo siguiente es un lista de sentencias y la descripción de lo que realizan: (Las partes entre corchetes de las sentencias son opcionales).
<dl><dt><dd>expresión1; while (expresión2) { sentencia; expresión3; } </dl>
Estas sentencias no son sentencias en el sentido tradicional. No son sentencias que se ejecuten. Su función se realiza en "tiempo de compilación".
Las funciones proporcionan un método para definir un cálculo que será ejecutado más tarde. Las funciones en bc siempre calculan un valor que devuelven a quien la ha llamado. La definición de las funciones son "dinámicas" en el sentido de que una función está indefinida hasta que se encuentra una definición en la entrada. Se usa esa definición hasta que se encuentra otra definición de función con el mismo nombre. La nueva definición reemplaza a la anterior. Una función se define como sigue:
<dl><dt><dd>define nombre ( parámetros ) { nueva_línea auto_lista lista_de_sentencias } </dl>
La ejecución de una función es simplemente una expresión de la forma "nombre(parámetros)".
Los parámetros son números o matrices (una ampliación). En la definición de la función, se definen cero o más parámetros listando sus nombres separados por comas. Los números son llamados por valor. Las matrices son llamadas por variable. Las matrices se especifican en la definición de parámetros mediante la notación "name[]". En la llamada a la función, los parámetros son expresiones completas para los parámetros que son números. Se usa la misma notación para pasar matrices que para definirlas en los parámetros. El nombre de la matriz se pasa a la función por variable. Como las definiciones de las funciones son dinámicas, el número de parámetros y los tipos se comprueban en el momento de llamar a la función. Cualquier discrepancia en el número o en el tipo de los parámetros provocará un error en tiempo de ejecución. También se provocará un error al llamar a una función no definida.
La auto_lista es una lista opcional de variables para uso "local". La sintaxis de esta lista (si se da) es "auto nombre, ... ;". (El punto y coma es opcional). Cada nombre es el nombre de una variable auto. Las matrices se pueden especificar con la misma notación que se usa en los parámetros. Los valores de estas variables se guardan en una pila al comienzo de la función. Entonces son inicializadas a cero y se usan en el transcurso de la función. Al finalizar la función, se recuperan de la pila los valores originales (en el momento de la llamada a la función). Los parámetros son realmente variables auto que se inicializan al valor proporcionado en la llamada a la función. Las variables auto son diferentes de las tradicionales variables locales en que si la función A llama a la función B, B puede acceder a las variables auto de A simplemente usando sus nombres, a no ser que la función B tenga variables auto del mismo nombre. Como tanto las variables auto como los parámetros son guardados en una pila, bc admite funciones recursivas.
El cuerpo de la función es una lista de sentencias de bc. De nuevo las sentencias van separadas por punto y coma o cambio de línea. La sentencia return hace que la función termine y devuelva un valor a la expresión que ha llamado a la función.. La primera forma, "return", devuelve el valor 0. La segunda forma "return ( expresión )", calcula el valor de la expresión y lo devuelve a la expresión que ha llamado la función. Hay un "return (0)" implícito al final de cada función. Esto permite a una función terminar y devolver 0, sin necesidad de una sentencia return explícita.
Las funciones también cambian el uso de la variable ibase. Todas las constantes en el cuerpo de la función son convertidas usando el valor de ibase en el momento de llamar a la función. Los cambios de ibase serán ignorados durante la ejecución de la función excepto para la función estándar read, que siempre usará el valor actual de ibase para la conversión de los números.
Si se invoca bc con la opción -l, una biblioteca matemática es pre-cargada y la escala por defecto se pone a 20. Las funciones matemáticas calcularán sus resultados a la escala definida en el momento de su llamada. La biblioteca matemática define las siguientes funciones:
En /bin/sh, lo siguiente asignará el valor de "pi" a la variable shell pi.
Lo siguiente es la definición de la función exponencial usada en la biblioteca matemática. Esta función está escrita en bc de POSIX.
<dl><dt><dd>scale = 20 /* Usa el hecho de que e^x = (e^(x/2))^2 Si x es lo suficientemente pequeño, se usa la serie: e^x = 1 + x + x^2/2! + x^3/3! + ... */ define e(x) { auto a, d, e, f, i, m, v, z /* Comprueba el signo de x. */ if (x<0) { m = 1 x = -x } /* Precondición x. */ z = scale; scale = 4 + z + .44*x; while (x > 1) { f += 1; x /= 2; } /* Inicialización de las variables. */ v = 1+x a = x d = 1 for (i=2; 1; i++) { e = (a *= x) / (d *= i) if (e == 0) { if (f>0) while (f--) v = v*v; scale = z if (m) return (1/v); return (v/1); } v += e } } </dl>
El siguiente código usa las características ampliadas de bc para implementar un simple programa para calcular balances. Es mejor guardar este programa en un fichero para poderlo usar varias veces sin tener que teclearlo cada vez.
<dl><dt><dd>scale=2 print "\n¡Programa de balances!\n" print " Recuerde, los depósitos son transacciones negativas.\n" print " Para salir introducir una transacción 0 .\n\n" print "¿ Balance inicial ? "; bal = read() bal /= 1 print "\n" while (1) { "Balance actual = "; bal "¿ transacción ? "; trans = read() if (trans == 0) break; bal -= trans bal /= 1 } quit </dl>
Lo siguiente es la definición de la función factorial recursiva.
<dl><dt><dd>define f (x) { if (x <= 1) return (1); return (f(x-1) * x); } </dl>
El bc de GNU se puede compilar (mediante una opción de configuración) para usar la biblioteca de entrada readline de GNU. Esto permite al usuario mayor posibilidad de edición de las líneas antes de mandarlas a bc. También permite tener un histórico de las líneas previamente introducidas. Cuando se selecciona esta opción, bc tiene una variable especial más. Esta variable especial, history es el número de líneas que se guardan en el histórico. Un valor de -1 significa que este número es ilimitado. Este es el valor por defecto. Dando un valor positivo a history se restringe el número de líneas a este valor. El valor 0 desactiva el histórico. Para más información, leer los manuales de usuario de las bibliotecas readline y history de GNU.
Esta versión de bc fue implementada a partir del borrador POSIX P1003.2/D11 y contiene varias diferencias y ampliaciones respecto a este borrador y las implementaciones tradicionales. No está implementada usando dc(1) como suele ser tradicional. Esta versión es un simple proceso que analiza el programa y ejecuta una traducción de este a un código de bytes (byte code). Hay una opción "indocumentada" (-c) que hace que el programa imprima en la salida estándar este código en lugar de ejecutarlo. Fue usada principalmente para depurar el analizador y preparar la biblioteca matemática.
Una mayor fuente de diferencias son las ampliaciones, tanto cuando son añadidas para dar más funcionalidad como cuando añaden nuevas características. Esta es la lista de las diferencias y ampliaciones.
<dl><dt><dd>a = 1 b = 2 </dl>tiene dos bloques y
<dl><dt><dd>{ a = 1 b = 2 } </dl>tiene un bloque. Cualquier error en tiempo de ejecución terminará con el actual bloque en ejecución. Un mensaje de aviso (warning) en tiempo de ejecución no terminará con el actual bloque en ejecución.
Los límites actualmente en vigor para este procesador bc son los siguientes. Algunos de ellos pueden haber cambiado en el proceso de instalación. Utilice la sentencia limits para ver sus valores actuales.
Las siguientes variables de entorno son procesadas por bc:
En la mayoría de las instalaciones, bc está completamente auto-contenido. Allí dónde el tamaño del ejecutable sea importante o el compilador de C no maneje las cadenas muy largas, bc leerá la biblioteca matemática estándar del fichero /usr/local/lib/libmath.b. (La situación real puede variar. Puede ser /lib/libmath.b ).
Si algún fichero dado en la línea de comando no se puede abrir, bc informará que el fichero no está disponible y terminará. Asimismo, hay errores en tiempo de compilación y de ejecución que deberían ser auto-explicativos.
La recuperación de errores no es muy buena todavía.
Notifique cualquier error a bug-gnu-utils@prep.ai.mit.edu. Compruebe que incluye la palabra ``bc'' dentro del campo ``Asunto:'' (``Subject:'').
Philip A. Nelson phil@cs.wwu.edu
El autor quisiera agradecer a Steve Sommars (Steve.Sommars@att.com) su gran ayuda probando la implementación. Me dio muchas sugerencias estupendas. Éste es un producto mejor gracias a su implicación.
This document was created by man2html, using
the manual pages.
Time: 20:28:05 GMT, January 21, 2005