/* */

24 de agosto de 2007

Problema 3.5

.
Enunciado
1 - Desarrollar una función stringToNum que permita convertir un string numérico (en cualquier base) a un longint (decimal). El prototipo de la función debe ser:

function stringToNum(s:string; base:integer): longint;

Ejemplo:

a:=stringToNum('1101',2); // retorna 13
b:=stringToNum('543',8); // retorna 355
c:=stringToNum('ABC',16); //retorna 2748

2 – Desarrollar las siguientes funciones:
  • function binToDec(sBin: string): longint
  • function octToDec(sOct:string):longint
  • function hexToDec(sHex:string):longint


Análisis
Antes de poder analizar el algoritmo tenemos que entender bien la forma en que se realiza la conversión entre las diferentes bases numéricas.

Primero veamos como hacemos para convertir entre binario y decimal:



Nota: numeramos los dígitos del número comenzando desde la derecha. Por lo tanto el primer dígito es el más a la derecha, el segundo dígito es el siguiente (hacia la izquierda) y el dígito n es el más a la izquierda.

La tabla anterior muestra que para convertir un número binario a su equivalente en decimal tenemos que aplicar la siguiente fórmula:


Donde n es la cantidad de dígitos que tiene el número y di es cada uno de los dígitos, comenzando desde la derecha.

Es decir: multiplicar cada uno de los dígitos (di) por la base (en este caso 2) elevada a la posición relativa del dígito dentro del número (comenzando desde cero).


Ahora veamos como convertir entre octal y decimal:



Resulta que es exactamente igual, pero cambiando el valor de la base. Ahora es 8:


Y de hexadecimal a decimal:



resulta la misma fórmula:



Solo cambia la base.


La fórmula en sí misma practicamente describe el algoritmo que tenemos que programar para resolver la función que plantea el enunciado.

La sumatoria con i variando entre n y 1 del dígito "sub i" multiplicado por la base elevada a la posición relativa del dígito (comenzando desde cero).



untBase.pas
 1:
2:unit untBase;
3:
4:interface
5: // recibe un string con caractere numericos y
6: // un entero que indica la base en la que esta
7: // expresado el numero contenido en el string
8: // por ejemplo stringToNom('100110',2) o bien
9: // por ejemplo stringToNom('AB43F',16) o bien
10: // por ejemplo stringToNom('6732',8)
11: function stringToNum(s:string
12: ; base:integer): longint;
13:
14: // recibe un string numerico base 2
15: // y retorna su valor numerico base 10
16: function binToDec(s:string):longint;
17:
18: // recibe un string numerico base 8
19: // y retorna su valor numerico base 10
20: function octToDec(s:string):longint;
21:
22: // recibe un string numerico base 16
23: // y retorna su valor numerico base 10
24: function hexToDec(s:string):longint;
25:
26:implementation
27:
28:// desarrollamos nuestra propia funcion potencia
29:// para calcular x "elevado a la" y
30:// notemos que no esta definida en la seccion
31:// interface. Esto es porque la funcion solo la
32:// utilizaremos dentro de esta unit. No es visible
33:// desde otros programas o units
34:function potencia(x,y:integer):longint;
35:var res:longint; i:integer;
36:begin
37: res:=1;
38: for i:=1 to y do begin
39: res:=res*x;
40: end;
41: potencia:=res;
42:end;
43:
44:// desarrollo de la funcion stringToNum
45:function stringToNum(s:string; base:integer): longint;
46:var di,exp,i,n: integer; sum: longint;
47:begin
48: // acumulador donde acumularemos cada una de las
49: // potencias de la base por el digito correspondiente
50: sum:=0;
51:
52: // n es la longitud del string (cantidad de digitos
53: // que tiene el numero
54: n:=length(s);
55:
56: // i variando de n a 1
57: for i:=n downto 1 do begin
58:
59: // obtengo el valor numerico del digito "sub i"
60: // ver explicacion mas abajo
61: if( s[i]<='9' ) then begin
62: di:=integer(s[i])-integer('0');
63: end else begin
64: di:=integer(s[i])-integer('A')+10;
65: end;
66:
67: // acumulo el digito por la base
68: // elevada a la (n-i)
69: sum:=sum+di*potencia(base,(n-i));
70: end;
71:
72: stringToNum:=sum;
73:end;
74:
75:// mas abajo desarrollamos las otras funciones
76:

Para obtener el dígito "sub i" preguntamos si s[i] es menor o igual a '9'. Es decir: si s[i] es '0', '1', ...,'9'. En este caso consideramos que di es:

di := integer(s[i]) - integer('0');

pero si no (o sea que s[i] es mayor que '9') entonces asignamos a di el siguiente valor:

di = integer(s[i]) - integer('A') + 10;

Todos los caracteres tienen asociado un valor numérico. Ese valor está definido la tabla ASCII.



Cuando hablamos de integer('A') estamos hablando del valor ASCII del caracter 'A' (que según la tabla es 65). Cuando hablamos de integer('0') estamos hablando del valor ASCII del caracter '0' (que es 48).

Suponiendo que s[i] es el caracter '8', Si restamos al valor ASCII de '8' el valor ASCII de '0' resulta 56 - 48 = 8 (justamente el valor numérico de '8'). Pero si s[i] fuese 'D' (en el caso que sea un dígito hexadecimal) entonces le restamos el ASCII de 'A' y le sumanos 10:

di := integer(s[i]) - integer('A')+10
di := integer('D') - integer('A')+10
di := 68 - 65 + 10
di := 13

Le asignamos a di el valor decimal del dígito hexadecimal 'D': 13.


Ahora, teniendo resuelta la función genérica stringToNum que permite convertir a decimal números expresados en cualquier base, podemos resolver las funciones pedidas en el punto 2 del enunciado.

 76:
77:function binToDec(s:string):longint;
78:begin
79: // retornamos lo que retorna stringToDec
80: // pasandole s y 2 (la base)
81: binToDec:=stringToNum(s,2);
82:end;
83:
84:function octToDec(s:string):longint;
85:begin
86: // retornamos lo que retorna stringToDec
87: // pasandole s y 8 (la base)
88: octToDec:=stringToNum(s,8);
89:end;
90:
91:function hexToDec(s:string):longint;
92:begin
93: // retornamos lo que retorna stringToDec
94: // pasandole s y 16 (la base)
95: hexToDec:=stringToNum(s,16);
96:end;
97:
98:end.
99:

Veamos un programa que utilice las funciones anteriores.

base.pas
 1:
2:uses untBase;
3:var s:string; base:integer;
4:begin
5: writeln( hexToDec('ABF5') );
6: writeln( octToDec('7521') );
7: writeln( binToDec('1101101') );
8: writeln( stringToNum('1101101',2) );
9:end.
10:






.

No hay comentarios: