/* */

7 de agosto de 2007

Capítulo 2

.
Operadores Aritméticos


Podemos realizar operaciones aritméticas en nuestros programas. Disponemos de los siguientes operadores.

  • (suma) +
  • (resta) -
  • (multiplicación) *
  • (división) /
  • (división entera) div
  • (resto en la división por) mod
y (entre otras) algunas funciones como:
  • (valor absoluto) abs
  • (raíz cuadrada) sqrt
Analizaremos algunos problemas en los que será necesario utilizar estos operadores.


Problema 2.1
Leer un valor numérico e indicar si es par o impar.


Análisis
Sabemos que un número es par si es divisible por 2. Y un número es divisible por 2 si el resto en la división por 2 es 0 (cero). Justamente el operador mod realiza la división entre dos valores pero da como resultado el resto de dicha división (no el cosiente). Entonces un número a es par si se verifica que a mod 2 es igual a cero.

problema2.1.pas
   1:
2:var v,resto: integer;
3:begin
4: write('Ingrese un valor: ');
5: readln(v);
6:
7: // mod retorna el resto de dividir v/2
8: resto := v mod 2;
9:
10: // si el resto es cero entonces v es par
11: if( resto = 0 ) then begin
12: writeln('Es par');
13: end else begin // resto no es cero... es impar
14: writeln('Es impar');
15: end;
16:end.
17:


Problema 2.2
Se ingresa por teclado una fecha expresada como un número entero de 8 dígitos con el siguiente formato: ddmmaaaa (donde los primeros dos dígitos corresponden al día, los dos siguientes corresponden al mes y los cuatro últimos corresponden al año).

Se pide mostrar un mensaje indicando: “La fecha que Ud. ingresó tiene día=dd, mes=mm y año=aaaa”.


Análisis

La resolución del ejercicio se limita a resolver una serie de operaciones aritméticas para poder descomponer la fecha ingresada que, como dice el enunciado será un número de 8 dígitos donde los dos primeros representan al día, los 2 siguientes el mes y los 4 últimos el año.

Consideremos como ejemplo que la fecha ingresada es: 25101970 (25 de octubre de 1970).

Si dividimos el valor de la fecha por 10 resulta ser:

25101970 / 10 = 2510197,0

y si lo dividimos por 100 será:

25101970 / 100 = 251019,70

Entonces si lo dividimos por 1000000 y tendremos:

25101970 / 1000000 = 25,101970.

Si de este resultado solo consideramos la parte entera obtenemos 25 que representa al día.

Para tomar la parte entera del cosiente de la división utilizamos el operador div (de Pascal).

dia:= fec div 1000000

Luego, si multiplicamos dia * 1000000 obtendremos 25000000. Si este valor se lo restamos a la fecha ingresada tendremos:

25101970 – 25000000 = 101970.

Si tomamos la parte entera del cosiente entre este valor y 10000 obtendremos 10 (el mes) y así podemos luego obtener el año.

problema2.2.pas
   1:
2:var
3: fec: longint;
4: dia,mes,anio: integer;
5:
6:begin
7: write('Ingrese una fecha (ddmmaaaa): ');
8: readln(fec);
9:
10: dia := fec div 1000000;
11: mes := (fec - dia*1000000) div 10000;
12: anio := fec - (dia*1000000+mes*10000);
13:
14: writeln('dia=',dia,' mes=',mes,' anio=',anio);
15:end.
16:


Problema 2.3
Ingresar un valor n, calcular la sumatoria de los primeros n números naturales.



Análisis
En cada vuelta del ciclo for vemos que a suma le asignamos lo que ya tenía más el valor de i. Decimos que “acumulamos el valor de i en la variable suma.

suma comienza en 0 (cero), en la primera vuelta del for le asignamos lo que tenía (0) más lo que vale i (1). El la segunda vuelta a suma le asignamos lo que tenía (1) más lo que vale i (2), y así.

problema2.3.pas
   1:
2:var
3: n,i,suma: integer;
4:
5:begin
6: write('Ingrese un valor: ');
7: readln(n);
8:
9: // suma es un acumulador, comienza desde cero
10: suma:=0;
11: for i:=1 to n do begin
12: // a suma le asigno lo que tenia mas uno
13: suma:=suma+i;
14: end;
15:
16: write('La suma de los primeros ',n);
17: writeln(' numeros naturales es ',suma);
18:
19:end.
20:


Problema 2.4
Se ingresa un valor n, calcular su facturial.


Análisis
El problema es practicamente igual al anterior pero en lugar de sumar multiplicamos.

Si el usuario ingresa el valor cero entonces será i mayor que n y no se entrará al while por lo tanto el resultado será 1 (y esto es correcto porque el factorial de 0 es 1 por definición).

El otro punto a considerar es que el multiplicador (fact) debe inicializarse en 1 ya que este valor es neutro para la multiplicación.

problema2.4.pas
   1:
2:var n,i,fact: real;
3:begin
4: write('Ingrese un valor: ');
5: readln(n);
6:
7: i:=1;
8: fact:=1;
9: while( i<=n ) do begin
10: fact := fact*i;
11: i:=i+1;
12: end;
13:
14: write('El factorial de ',n, ' es ', fact);
15:
16:end.
17:


Máximos y Mínimos

Es muy común que surja la necesidad de calcular el máximo o el mínimo valor de un conjunto de datos. Los siguiente problemas muestran como resolver estas situaciones.


Problema 2.5
Leer un conjunto de números que finaliza con un valor 0. Indicar cual es el mayor (máximo).
a - Considerar que todos los números son positivos.
b - Considerar que pueden venir números positivos y negativos.

Solución punto a................Solución punto b

Análisis
A la izquierda vemos la solución del caso a. Utilizamos una variable max para almacenar el mayor número a medida que detectamos que es mayor que el máximo detectado hasta el momento.

La variable max debe inicializarse en un valor lo suficientemente bajo de forma tal que cualquiera de los números ingresados resulte mayor. Como el enunciado plantea que todos los números serán positivos entonces 0 (cero) es un valor adecuado para esta variable.

Luego, ingresamos en un ciclo repetitivo que iterará mientras v sea distinto que cero ya que el usuario ingresará el valor cero para indicar el fin de datos.

Dentro del ciclo, por cada valor leido preguntamos si es mayor que el máximo (max). Si es así entonces lo guardamos en la variable max.

A la derecha vemos la solución para el caso b. Es idéntica a la anterior. La única diferencia es que inicializamos la variable max con el primer valor leido. Esto se debe a que el conjunto de datos no está acotado inferiormente. No podemos escoger un valor lo suficientemente bajo como para asegurar que el primer valor leido será mayor.

Podemos decir entonces que cuando tenemos que identificar el máximo valor de un conjunto debemos utilizar una variable inicializada con una cota inferior de dicho conjunto. Y si el conjunto no está acotado entonces debemos inicializar la variable con el primer elemento del conjunto.

Muchas veces la cota del conjunto la determina el contexto del problema. Si hablamos de edades de personas entonces la cota inferior será 0 (o cualquier número negativo) y la cota superior será cualquier valor exagerado para una edad. 200, 300, etc. Ninguna persona puede vivir 200 años (salvo que hablemos de Matusalén).

problema2.5a.pas
   1:
2:var max,v: integer;
3:begin
4:
5: // inicializamos a la cota inferior del conjunto
6: max:=0;
7:
8: // leemos un valor por teclado
9: write('Ingrese un valor: ');
10: readln(v);
11:
12: while( v<>0 ) do begin
13:
14: // si el valor leido es mayor que el maximo...
15: if( v>max ) then begin
16: max:=v; // el maximo ahora es el valor v
17: end;
18:
19: // leemos el siguiente valor
20: write('Ingrese un valor: ');
21: readln(v);
22:
23: end;
24:
25: writeln('Maximo: ', max);
26:end.
27:

La codificación del problema 2.5b queda a cargo del lector.

Analogamente podemos plantear el siguiente problema para identificar el menor de los elementos de un conjunto numérico.


Problema 2.6
Leer un conjunto de números que finaliza con un valor 0. Indicar cual es el menor (mínimo).
a - Considerar que todos los números son menores que 1000.
b - Considerar que puede venir cualquier número positivo o negativo.

Solución punto a................Solución punto b

Análisis
El análisis es similar al que realizamos para el problema del máximo. En una variable min almacenaremos cada número que detectemos que es menor que todos los números ingresados hasta el momento. Por eso la variable min debe inicializarse con alguna cota superior del conjunto.

Para el primer caso (todos los números serán menores a 1000) podemos considerar que 1000 es una cota superior ya que cualquiera sea el valor de v seguro será menor que 1000.

Luego (dentro del ciclo repetitivo) debemos preguntar si v es menor que min. Si es así entonces asignamos min a la variable v.

Para el segundo caso, como el conjunto no está acotado superiormente inicializamos la variable min con el primer valor leido. Así, este será el mínimo hasta que leamos otro valor que resulte menor.

problema2.6a.pas
   1:
2:var min,v: integer;
3:begin
4:
5: // inicializamos a la cota superior del conjunto
6: min:=1000;
7:
8: // leemos un valor por teclado
9: write('Ingrese un valor: ');
10: readln(v);
11:
12: while( v<>0 ) do begin
13:
14: // si el valor leido es menor que el minimo...
15: if( v<min ) then begin
16: min:=v; // ahora tomamos como minimo a v
17: end;
18:
19: // leemos el siguiente valor
20: write('Ingrese un valor: ');
21: readln(v);
22:
23: end;
24:
25: writeln('Minimo: ', min);
26:end.
27:

La codificación del problema 2.6b queda a cargo del lector.


Tratamiento de Cadenas de Caracteres

Los lenguajes de programación proveen funciones para trabajar con los caracteres contenidos en un string (cadena de caracteres).

Es muy común tener que convertir números a strings, strings a números, querer obtener solo una parte de un string, etc. A este tipo de operaciones lo llamamos "tratamiento de cadena" (de caracteres).


Convertir entre Números y Strings

Con las funciones val y str podemos convertir valores de un tipo de datos a otro. Es decir: teniendo una variable de algún tipo numérico podemos convertir su valor a un string y teniendo un string compuesto solo de caracteres numéricos podemos convertirlo a un tipo numérico.

El siguiente programa muestra como utilizar estas dos funciones: str para convertir de número a cadena y val para convertir de cadena a número.

cadenas1.pas
   1:
2:var
3: sValor1,sValor2:string[20];
4: iValor:integer;
5: rValor:real;
6:
7:begin
8: iValor:=10;
9:
10: // almacena un sValor1 un string '10'
11: str(iValor, sValor1);
12:
13: // mostramos el valor de sValor1
14: writeln(sValor1);
15:
16: // asignamos un valor a sValor2
17: sValor2:='20.5';
18:
19: // asignamos a rValor el valor
20: // numerico de sValor2
21: val(sValor2,rValor);
22:
23: // mostramos el valor de rValor
24: writeln(rValor);
25:
26:end.
27:


Longitud de un String y acceso a sus Caracteres

Con la función length obtenemos la cantidad de caracteres que tiene un string. Por ejemplo, la cadena 'Hola' tiene 4 caracteres numerados de 1 a 4.

También podemos acceder directamente a los caracteres del string. Si s vale 'Hola' entonces s[1] vale 'H', s[2] vale 'o', s[3] vale 'l' y s[4] vale 'a'.

Podemos reemplazar un caracter del string asignando el nuevo caracter directamente en la posición deseada. Por ejemplo, si s vale 'Hola', luego de hacer s[2]:='M' el valor de s
será: 'HMla'.

El siguiente programa muestra ejemplos sobre estos temas.

cadenas2.pas
   1:
2:var
3: s:string[20];
4: i,n:integer;
5:begin
6: s:='Hola, soy Pablo';
7: n:=length(s);
8:
9: writeln('Cantidad de caracteres: ',n);
10: writeln('En la posicion 4 hay un: ',s[4]);
11: writeln('En la posicion 11 hay un: ',s[11]);
12:
13: // modifico el caracter en la posicion 11
14: s[11]:='H';
15:
16: for i:=1 to n do begin
17: writeln(s[i]);
18: end;
19:end.
20:


Substrings

Se llama substring a una "subcadena" de caracteres. Por ejemplo: si consideramos la cadena: "Esto es el HolaMundo.pascal" entonces entre el caracter número 1 y el caracter número 9 tenemos la subcadena: "Esto es e". Y entre el caracter número 13 y el 16 tenemos la subcadena: "olaM".

La función de Pascal que permite obtener substrings es la función copy. Esta función recibe el string original, la posición inicial de la subcadena y la cantidad de caracteres que queremos incluir contando desde la posición inicial.

cadenas3.pas
   1:
2:var s,aux1,aux2: string[20];
3:begin
4: s:='Esto es el HolaMundo.pascal';
5: // la funcion copy recibe el string original,
6: // desde y nCaractes, y retorna el substring
7:
8: // asigna en aux1 el valor 'Esto es e'
9: aux1:=copy(s,1,9);
10: writeln(aux1);
11:
12: // asigna en aux2 el valor 'olaM'
13: aux2:=copy(s,13,4);
14: writeln(aux2);
15:
16: writeln('Llamandola directamente: ',copy(s,4,12));
17:end.
18:

Contando con la función copy de Pascal podemos programar nuestra propia función subString de la siguiente manera:

testSubstring.pas
   1:
2:// recibe el string original, desde y hasta
3:// (desde inclusive, hasta NO inclusive)
4:function subString(s:string; d,h:byte):string;
5:begin
6: subString:=copy(s,d,h-d);
7:end;
8:
9:// programa principal para probar la funcion
10:var x:string;
11:begin
12: // --- POSICION DE LOS CARACTERES ---
13: // 1 10 20
14: // 123456789012345678901234567
15: x:='Esto es el HolaMundo.pascal';
16:
17: // debe imprimir: "Esto es e"
18: writeln( subString(x,0,9) );
19:
20: // debe imprimir: "es el HolaM"
21: writeln( subString(x,6,17) );
22:
23: // debe imprimir: ".pascal"
24: writeln( subString(x,21,28) );
25:end.
26:


Convertir entre Mayúsculas y Minúsculas

Con las funciones upCase y lowerCase podemos convertir un string a mayúsculas y a minúsculas respectivamente.

cadenas4.pas
   1:
2:var s,may,min:string[20];
3:begin
4: s:='Hola, Que Tal?';
5: // convierte a mayuscula
6: may:=upCase(s);
7:
8: // convierte a minuscula
9: min:=lowerCase(s);
10:
11: writeln(may);
12: writeln(min);
13:end.
14:


Problema 2.7
Leer una cadena e indicar si la cadena ingresada es capicúa o no.




Análisis
Para resolver este problena debemos analizar las características de las cadenas capicúa. Por ejemplo la palabra "reconocer". Tiene 9 caracteres y podemos ver que el primero es igual al último. El segundo es igual al anteúltimo y así sucesivamente.

Manejamos dos variables i (apuntando al primer caracter) y j apuntando al último (para esto utilizamos la función length). Con esto podemos comparar los caracteres s[i] y s[j]. Si son distintos entonces podemos determinar que la cadena no es capicúa. Si son iguales entonces incrementamos i y decrementamos j para comparar el segundo con el anteúltimo y así.

problema2.7.pas
   1:
2:var
3: s:string[100];
4: i,j: integer;
5: esCapicua:boolean;
6:begin
7: write('Ingrese la cadena: ');
8: readln(s);
9:
10: i:=1;
11: j:=length(s);
12:
13: esCapicua:=true;
14:
15: while( (i<=j) AND esCapicua ) do begin
16: if( s[i] <> s[j] ) then begin
17: esCapicua:=false;
18: end else begin
19: i:=i+1;
20: j:=j-1;
21: end;
22: end;
23: if( esCapicua ) then begin
24: writeln('Felicidades, ES CAPICUA!');
25: end else begin
26: writeln('Lamentablemente NO ES CAPICUA!');
27: end;
28:end.
29:






.
Algoritmos y Estructuras de Datos UTN - UBA.

4 comentarios:

Anónimo dijo...

Hola! Una pregunta: En el gráfico que mostrás relacionado al problema "Capicua" decís que si s[i]<>s[j] entonces esCapicua se vuelve verdadero, pero no es que se pone en falso en ese caso?Espero tu respuesta! Muchas Gracias.
PD: El blog está muy interesante!

PabloSZ dijo...

Tenés razón, el gráfico está mal. Pero fijate que en el código está bien. En el if se debe asignar FALSE en lugar de TRUE.

Saludos ,
Pablo.

Anónimo dijo...

hola kisiera k me muestren un ejemplo de codigo srt y val porfavor lo mas antes posible gracias

Anónimo dijo...

Hola q tal, qria decir q me parece q esta mal el ejercicio 2.4.. ya q la variable tiene q ser integer no real
muchos saludos y muchas gracias por este blog es explendido!!!