UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. 26. Representación de números. Conversiones 26.1. Representación y conversión. Los números son representados internamente, en un computador digital, en sistema binario. Externamente se representan mediante secuencias de caracteres. Los procesos de entrada y salida de números evidentemente están basados en procedimientos de conversión entre la representación externa y la interna y viceversa. Gran parte de las facilidades que un lenguaje de programación ofrece a un programador, se encuentran en la abstracción de la representación interna de los números. Específicamente, en Pascal, nos referimos a los procedimientos read y write con argumentos enteros y reales. Asumiremos que se dispone de procedimientos para leer y escribir caracteres. 26.2 Funciones primitivas. Se desarrollan algunas funciones primitivas que nos serán útiles. function esdigito(ch:char):boolean; begin esdigito:=('0'<=ch) and (ch<='9') end; function valor(ch:char):integer; begin valor:=ord(ch)-ord('0') end; function caracter(x:integer):char; begin caracter:=chr(x+ord('0')) end; Debe asegurarse que el argumento de caracter esté en el rango: 0 <= x < 10 Prof. Leopoldo Silva Bijit. 07-07-2003 308 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. 26.3 Lectura de enteros. En sistemas posicionales la secuencia: 123 , se interpreta según: 123 = 1*100 + 2*10 + 3 y también : ((1*10)+2)*10+3 Asumiremos que en la variable global ch, de tipo carácter, se encuentra el carácter que aún no ha sido procesado. La constante b es la base, 10 en este caso. procedure leaentero(var x:integer); begin while ch=' ' do read(ch); x:=0; while esdigito(ch) do begin x:=x*b+valor(ch); read(ch) end end; Nótese que después de ejecutado leaentero, en ch queda el siguiente carácter, diferente de un dígito. Esto se denomina lectura por adelantado (lookahead). Además, se descartan los espacios antes de la secuencia de un entero. En caso de no corresponder a un entero, no avanza en la secuencia de entrada y asigna valor cero al entero; esto obviamente es una limitación. Modificar el algoritmo para detectar errores en la entrada y para limitar, el largo de la secuencia, al máximo entero representable; o bien, para detectar el rebalse y pedir reentrar el entero. Debe notarse que el procedimiento lee desde el archivo estándar de entrada; y debe modificarse si se desea leer desde un archivo de texto externo. También es preciso efectuar modificaciones si se desea leer números con signo. Prof. Leopoldo Silva Bijit. 07-07-2003 309 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. Con este primer ejemplo, debe destacarse la gran cantidad de detalles que quedan abstraídos cuando se emplea la instrucción read con argumento entero. 26.4 Lectura de fracciones. El siguiente procedimiento permite leer una fracción decimal. El número debe ser menor que uno. procedure leefraccion(var x:real); var e : real; begin while (ch=' ') or (ch='0') do read(ch); x:=0; e:=b; if ch='.' then begin read(ch); while esdigito(ch) do begin x:=x+valor(ch)/e; e:=b*e; read(ch) end end end; No se detectan fracciones mal escritas. Debido a que el algoritmo trabaja con números reales, existirá un error inherente en la conversión. Tampoco se limita el largo de la secuencia de la fracción de entrada; si ésta es muy larga existirán errores por vaciamiento en la división. El signo de la fracción no es considerado en el algoritmo. Los procedimientos anteriores, al trabajar con números decimales, siguen siendo abstracciones. Los procedimientos reales deben trabajar en aritmética binaria, y describirse en instrucciones de más bajo nivel. 26.5. Lectura de reales punto fijo. Puede diseñarse este procedimiento en términos de los anteriores. Prof. Leopoldo Silva Bijit. 07-07-2003 310 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. 26.6. Escritura de enteros. Asumiremos enteros de n cifras. procedure escribaentero(x:integer); var i : 1..n; r : array [1..n] of char; begin for i:=n downto 1 do begin r[i]:=caracter(x mod b); x:=x div b; end; for i:=1 to n do write(r[i]) end; El procedimiento debe modificarse para considerar el signo y también si se desea suprimir los ceros a la izquierda; en este caso debe usarse while en lugar de for. También puede pasarse un parámetro con el ancho del número. 26.7. Escritura de fracción. procedure escribafraccion(x:real); var i : 0..n ; v : integer; begin write('.'); i:=0; repeat x:=b*x; v:=trunc(u); write(caracter(v)); u:=u-v; i:=i+1 until i=n end; El procedimiento no contempla signos, y tampoco el máximo representable. La aproximación es por truncamiento; pero podría modificarse para aproximar por redondeo. 26.8. Cambio de base en números punto flotante. Prof. Leopoldo Silva Bijit. 07-07-2003 311 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. Una representación interna usual de números reales es en notación punto flotante en sistema binario. Es decir, un número real r se representa por un par de números enteros tales que: r = m * b^e Donde m es la mantisa y e el exponente. La mantisa suele normalizarse, y es tal que: 1/b <= m < 1 ; donde b es la base. Internamente la base suele ser una potencia de dos. Si b = 2^k , un aumento o decremento en uno del exponente e, significa una multiplicación o división de m por 2^k. Esto se implementa por un corrimiento de k bits a la izquierda y derecha respectivamente. Sin embargo, en forma externa, la base suele ser 10. Por esta razón, es necesario disponer de procedimientos que conviertan un número punto flotante en una base dada en otra. Explicaremos el algoritmo efectuando las operaciones en sistema decimal, para beneficio del lector. Sin embargo, los procedimiento básicos para realizar estas operaciones deben plantearse con operaciones en sistema binario, para las cuales existen instrucciones en el repertorio de cualquier procesador. Dado un número : r = m1*b1^e1 Se desea obtener su representación equivalente en base b2: r = m2*b2^e2 En la práctica, b1 y b2 son 10 y 2, y viceversa. procedureconvierta(varm:real;e1:integer;var e2:integer); begin e2:=0; if e1>=0 then Prof. Leopoldo Silva Bijit. 07-07-2003 312 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. while e1>0 do begin m:=b1*m; e1:=e1-1; while m>=1 do begin m:=m/b2; e2:=e2+1 end end else repeat m:=m/b1; e1:=e1+1; while m <(1/b2) do begin m:=m*b2; e2:=e2-1 end until e1=0 end; El algoritmo es ineficiente, pues el número de operaciones es proporcional a e; además es inexacto debido a las aproximaciones de redondeo o truncamiento para mantener la mantisa de un largo dado. La esencia del algoritmo es alternar las multiplicaciones (o divisiones) de m por b1, con las divisiones (o multiplicaciones) por b2, de tal forma que m se mantenga normalizada; o bien, que se mantenga en el rango: 1/b <= m < b ; con b = b1*b2 Puede verificarse, a través del algoritmo que: 0.32*2^4 = 0.512*10^1 Nótese el diferente tratamiento para los números con exponente positivo y negativo. 26.9 Rutinas más reales de lectura y escritura. En User Manual pág. 122 a 125 se encuentran procedimientos generales para leer y escribir números reales. En ellos se mantienen los números reales dentro del rango de representación interna del computador empleado. Se usan 48 bits para la mantisa y 11 bits para el exponente, y 1 para el signo de la mantisa. El largo de la palabra es 60 bits. Prof. Leopoldo Silva Bijit. 07-07-2003 313 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación en Pascal Capítulo 26. Representación de números. Conversiones. Se leen números de acuerdo a la sintaxis de números reales en Pascal. En caso de vaciamiento se asigna cero al valor leído. Existe una función que evalúa 10^e a través de operaciones primitivas de corrimiento en sistema binario. La rutina de escritura maneja el parámetro de escritura y también incorpora la idea de redondeo para un número de cifras decimales dado. En la parte de escritura aparecen algunos números mágicos. Se emplean en operaciones enteras escaladas, en las que aparecen números reales aproximados a enteros. El factor de escala empleado es el máximo entero del tipo que se esté usando. El segmento que efectúa la conversió n de un entero a una secuencia de caracteres puede simplificarse, efectuando divisiones enteras por 10, en lugar de aritmética entera escalada. Los mismos programas, pero con algunos comentarios adicionales se encuentran en Algorithms + Data Structures = Programs, págs. 45 a 49. 26.10 Abstracción de la Entrada/Salida. Lo destacable de este capítulo es que un lenguaje de alto nivel oculta al programador los detalles de conversión de números de representación interna a externa y viceversa. Estudiando los programas planteados pueden observarse la complejidad de las operaciones que son asumidas implícitamente cuando se emplean las sentencias read y write. Prof. Leopoldo Silva Bijit. 07-07-2003 314