[ Foro de Pascal ]

Problema en Pascal

12-Sep-2011 13:20
Isis Fajardo
10 Respuestas

Hola,tengo un examen mañana y ando preparándome el tema de tablas, matrices y vectores y ando buscando ejemplos que me ayuden a entenderlos mejor.

1)¿Cómo podría hacer un procedimiento que modificase una tabla de dos dimensiones (MxN) de manera que: 1) calcule la media de los elementos positivos y 2) reemplace los elementos negativos porla media calculada?

2)Estoy intentando hacer un problema en Pascal y me encuentro atascada. El programa debe leer un número indeterminado de valores positivos enteros por teclado y calcular luego la media de los valores leídos, el máximo y el mínimo. El proceso acaba cuando se lee un número negativo.

Aquí expongo lo que llevo hecho de momento, a ver si me pueden ayudar:

Program Enteros;
uses crt;
var
valor, primer valor, maximo, minimo, suma, numvalores: integer;
media: real;
begin
clrscr;
suma:= 0;
numvalores:= 0;
minimo:= 10;
maximo:= 0;
writeln('Por favor, introduzca los valores que desee: ');
read(primervalor);
if (primervalor<0) then
writeln('Disculpe, el programa se ejecutará cuando introduzca, al menos, un valor positivo.')
else
if (primervalor>0) then
begin
read(valor);
.
.
.

end.

P.D: El primervalor se me ocurrió por si se introducía en primer lugar un número negativo, no tendría sentido que se ejecutara. Pero si a continuación el segundo if se ejecuta, creo que estando como está, el primer valor introducido no se tendría en cuenta para calcular la media, minimo y máximo, ¿no?. También pensé en usar un: for valor :=0 to n do y proceder a meter los subprogramas para el cálculo de la media, maximo y minimo. El de la media tengo pensado hacerlo del tipo

i:=0;
suma:=0;
 begin
   repeat
   readln(valor);
   if(valor>=0) then
   suma:=suma+valor;
   i:=i+1;
 end;
if(valor<0) then
writeln(suma/i);

¿Qué opinan? Muchas gracias de antemano.


12-Sep-2011 14:37
Isis Fajardo

Lo de la media está incorrecto, creo que mejor sería:

i:=0;
suma:=0;
 begin
   repeat
   readln(valor);
   if(valor>=0) then
   suma:=suma+valor;
   i:=i+1;
   until(valor<0);
writeln(suma/i);

Agradezco cualquier ayuda que me pueda prestar.


12-Sep-2011 20:43
Isis Fajardo

Sigo enfrascada en este problema, y ya le he dado algo más de forma:

Program Dos;
uses crt;

var
valor, maximo, minimo, suma, i, n: integer;
media: real;

begin
suma:=0;
i:=0;
minimo:=10;
maximo:=0;

writeln('Este programa lee los valores positivos que usted introduzca y procede a calcular su media, su maximo y su minimo tras introducir cualquier valore negativo.');
writeln('Introduzca valores: ');
readln(valor);

repeat
readln(valor);
if (valor>=0) then
suma:=suma+valor;
n:=n+1;
media:=suma/n;
if (valor<minimo) then
minimo:=valor;
if (valor>maximo) then
maximo:=valor;
until (valor<0);

writeln('La media es: ', media);
writeln('El mínimo es: ', minimo);
writeln('El máximo es: ', maximo);
writeln('Pulse cualquier tecla para finalizar...');
readkey;
end.

El problema ahora es que solo se ejecuta para el primer valor que meto.¿Cómo puedo hacer que se siga ejecutando y sólo pare cuando meta un valor negativo? Por favor, agradezco su ayuda urgente, muchas gracias.

Edito: Problema solucionado, ahora pasa que me cuenta el número negativo para la media y el mínimo.


12-Sep-2011 21:18
Antonio P.G.

Hola, seré breve pero intentaré ser lo más claro posible.

No es necesario que proporciones un valor de arranque a las variables "minimo" y "maximo", puesto que dependen completamente de los números que se vayan a leer.

Elimina el "readln (valor);" que has puesto antes del "repeat". Si no, leerás dos valores seguidos y el primero no se tendrá en cuenta.

Dentro del "repeat...until" tendrás que hacer ciertas comprobaciones, y en un cierto orden. Lo primero es, como lo tienes, leer el valor. Después:

1- Si es cero o positivo, realizas los siguientes pasos ("if valor <= 0) then begin... end;").

2- Si se trata del primer valor que lees, entonces "maximo" y "minimo" valen ese valor. Si no, es decir, si ya has leído más valores antes, entonces comparas el valor que acabas de leer con el máximo y el mínimo. (Esto es sencillo: si es mayor que el máximo, el máximo pasará a ser el valor que acabas de leer, y de forma análoga con el mínimo).

Para saber si es la primera vez que lees un valor puedes jugar con una variable boolean ("primeravez", por ejemplo), que arranque en false, y cuando hayas leído por primera vez (es decir según asignas el valor recién leído al máximo y al mínimo, le das el valor TRUE).

3- Sumas 1 al contador.

4- Acumulas el valor en la suma. Y aquí ya se cerraría el "end" del condicionante del paso 1.

Para el until, la condición que pusiste.
Después del bucle es cuando calculas la media, y presentas los resultados.

Hay otra forma de hacerlo con "while", más elegante y con un menor coste en tiempo (algorítmicamente hablando), pero como ya tenías el "repaet...until", te lo dejo así.

Espero haberte servido de ayuda. Ya nos contarás qué tal el examen.

¡Ciao!

P.D.: No es necesario usar "crt". En vez de "readkey;" puedes utilizar un "writeln ("Pulse ENTER para salir.") u detrás un "readln;".


12-Sep-2011 21:37
Isis Fajardo

Muchísimas gracias, Antonio. Voy a ponerme manos a la obra para corregir lo que me has comentado y dejar así el código más claro. Por cierto, si te apetece puedes ponerlo en "while", a veces es bueno comparar y que la gente vea cómo lo entiende mejor y decidir así por cuál se decanta.

Espero también haber servido de ayuda para la gente que tenía problemas con este mismo ejercicio, ya que lo he visto en un par de sitios aún sin respuesta. Con un poco de ayuda de todos una se anima a programar, así da gusto aprender :)

Muchas gracias por los consejos. Seguiré visitando esta página para seguir aprendiendo con vosotros :)


12-Sep-2011 22:01
Antonio P.G.

Genial. Mañana si tengo tiempo escribo la solución del "while".

Perdona, se me olvidó el primer ejercicio:

Hay dos partes: lectura y escritura.

Primero, leemos toda la matriz, con un par de "for" anidados, y si el valor no es negativo, lo procesamos:

"
for i:=1 to N do
  for j:=1 to M do
     if not (matriz[i,j] < 0) then begin
       suma:= suma + matriz[i,j];
       Inc (contador);  (*Incrementamos en uno la variable "contador". *)
     end;
"

Obviamente, "suma" y "contador" se arrancan en cero. Después calculamos la media. Y luego, recorremos de nuevo la matriz. En este caso, si el número es negativo la instrucción a utilizar será:

"matriz[i,j]:= media;"

¡Espero que valga! (Lo siento, pero tengo prisa :-P ).

P.D.: N y M son constantes predefinidas.


12-Sep-2011 22:06
Nacho Cabanes (+84)

Isis, sólo dos comentarios a la última versión de tu fuente que has puesto, y en los que creo que no ha caido Antonio:

- Tu variable "n" no tiene un valor inicial. Eso es MUY peligroso. Algunos lenguajes, y en ciertas condiciones, aseguran que una variable a la que tú no das valor tendrá el valor 0 (o una texto vacío, si se trata de una cadena). Pero como otros lenguajes no lo hacen, es preferible acostumbrarse a dar un valor inicial (n := 0;). Por ejemplo, en C eso sería un error muy difícil de descubrir, porque el valor inicial sería basura (lo que casualmente contuviera la dirección de memoria que el compilador ha reservado para la variable "n").

- Cuidado con el "repeat": como la condición de finalización se comprueba al final del bloque, si el usuario introduce un valor negativo, éste se sumará y se calculará como parte de la media.  Necesitas un "if" para no sumarlo (ni aumentar el contador) si es negativo. Para asegurarte de que todo va bien, siempre prueba tus programas con varios conjuntos de datos simples y cuyo resultado conozcas. Por ejemplo, la media de (2, 4) debería ser 3. En tu programa, puede ocurrir que si tecleas 2, 4, -3, se sume ese -3 y te diga que la media es 1.


Y, de paso, dos detalles de poca importancia:

- No estás usando para nada la variable i. Intenta no conservar las variables que no estés usando. Por ejemplo, si en otra parte del programa pones "n" en vez de "i", puede provocar un fallo muy difícil de encontrar.

- Intenta que el título de tu mensaje sea descriptivo. Estás en un foro de Pascal, así que casi cualquier conversación será un "problema en Pascal". Algo como "media de un vector" sería más claro, y ayudaría a otros usuarios a responderte, o a encontrar conversaciones anteriores que resuelvan sus dudas.


La versión con un vector unidimensional la tienes casi terminada. Cuando esa funcione, intenta hacerlo con una matriz bidimensional de MxN, pero no antes de que funcione la versión básica, para asegurarte de que entiendes los fundamentos.


12-Sep-2011 22:17
Isis Fajardo

Muchísimas gracias a los dos. De verdad que vuestras explicaciones son muy buenas.

Siempre me dijeron que explicar programación era una tarea muy díficil, a veces imposible. Con vosotros es posible.

Un saludo, voy a seguir estudiando y compilando :)


12-Sep-2011 23:45
Antonio P.G.

Hola,

Jope, Nacho, sí que se me había pasado. La verdad es que prácticamente no había mirado el código, porque iba con mucha prisa. Espero ir con menos la próxima vez.

Gracias.

¡Ciao!


13-Sep-2011 23:40
Antonio P.G.

Hola,

Dejo aquí lo solución que propuse con un bucle "while", que implica un menor coste computacional que la anterior solución (aunque con las máquinas de hoy en día, esta diferencia ni se nota...):

-------------------------------
program Numeritos (input,output);

const
 N_decimales = 2;  { Número de decimales a mostrar. }

var
  contador : integer;    { Para contar las vueltas. }
  max, min, acumulador,               { Sin explicación... }
  valor    : real;  { Cada uno de los valores leídos. }
begin
  writeln ('Introduce números positivos. Escribe cada uno y pulsa ENTER después. Te diré al final la media de todos, el mayor y el menor. Para parar, introduce un número negativo.');
 contador:= 1;
  write ('Número ',contador,':');
  readln (valor);
  if not (valor < 0) then begin
     max:= valor;
     min:= valor;
     acumulador:= 0;
     while not (valor < 0) do begin
       if valor > max then
          max:= valor;
       if valor < min then
          min:= valor;
       acumulador:= acumulador + valor;
       Inc (contador);
       writeln ('Número ',contador,':');
       readln (valor);
     end;
     writeln ('¡Introdujiste un valor negativo! Resultados:');
     writeln ('Media: ',acumulador/(contador-1):0:n_decimales);
     writeln ('Máximo: ',max:0:N_decimales);
     writeln ('Mínimo: ',min:0:N_decimales);
  end
  else
    writeln ('¡No introdujiste ningún valor positivo! Adiós.');
end.

-------------------------------------

Notas:
1- En el bucle anterior chequeábamos en cada vuelta el hecho de que fuese la primera vez que se imputaba un valor. Ahora ya no.

2- En la primera línea de resultados, escribo "contador-1" porque el último número introducido será negativo, y por tanto no será tenido en cuenta para operar. Es decir, si al termiar el bucle, "contador" vale 5, será porque hay 4 números no negativos y uno negativo.

3- En las condiciones de negatividad, no pongo "while valor >= 0", por ejemplo. Esto es, porque los reales no pueden comparase con un igual ("valor" es real). Es decir, esto siempre será falso:

"valor = 3.5" (o cualquier otro número).

(Corrígeme por favor, Nacho, si me equivoco).

4- Lo he hecho de forma que se ejecuten las operaciones necesarias. Es decir, se sabe que "acumulador" arrancará en cero, pero sólo lo asigno si sé que se va a utilizar (de ahí que lo meta en el primer condicionante). Si no, podría ser una operación inútil.

5- Ni siquiera lo he compilado, pero espero que funcione... Ja ja.

Espero que esto haya servido.

¡Un saludo!


14-Sep-2011 10:15
Nacho Cabanes (+84)

No tienes por qué pedir disculpas, Antonio. Eres de gran ayuda, sólo faltaba eso. Tu respuesta era (casi) impecable.  ;-)

En cuanto a la última respuesta que has publicado, tienes razón: es preferible no comprobar igualdad con un número real, porque puede no funcionar correctamente según de qué lenguaje (e incluso compilador se trate). Por ejemplo, algo como

x := 3.5;
if x = 3.5 then ...

puede no llegar a cumplirse porque la variable x sea de simple precisión (de modo que valga por ejemplo 3.50001) y el valor de comparación se tome como de doble precisión (y sí valga 3.5 o algo como 3.499999999999).

Aun así, en la mayoría de casos no es un problema, y en lenguajes "conflictivos", como C, muchos compiladores darían el aviso de que se están comparando datos de distinto tipo y se pueden obtener resultados inesperados.






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)