Duda rápida de C++: do... while...

Aquí podrás hablar de cualquier cosa relacionada con la tecnología y la informática: software, hardware, internet, problemas con tu PC, robótica, I+D+i, etc.

Moderator: Viento

User avatar
will-o-the-wisp
Panacea Definitiva
Panacea Definitiva
Posts: 2466
Joined: 20 Dec 2009, 14:00
PSN ID: oh_mike_dog
Twitter: @oh_mike_god
Location: Zaragoza

Duda rápida de C++: do... while...

Post by will-o-the-wisp » 26 May 2011, 18:48

Me han dado un código fuente para la práctica de Álgebra II que tengo mañana, al cual le tendré que hacer las modificaciones que me pidan allí. Este programa busca el autovalor máximo y el autovector correspondiente de una matriz simétrica por medio de un proceso iterativo.

El algoritmo no comprueba que el usuario está introduciendo una matriz simétrica, es decir, que coincide con su transpuesta (o lo que es lo mismo, que cada elemento A[i][j] es igual al elemento A[j][i]). No sé si me pedirán modificar esto, pero lo voy a hacer porque además me resultará más cómodo mañana saber si estoy metiendo matrices simétricas.

Una forma es especificarle al programa que no le pida al usuario introducir el elemento A[j][i] si ya ha introducido el A[i][j], pero prefiero que dé un error y pida introducir una matriz nueva.

Este es el algoritmo para que el usuario introduzca los elementos de la matriz.

Code: Select all

for(i=0;i<N;i++) 

  for(j=0;j<N;j++)
  {
    printf("\nelemento [%d][%d]= ",i,j);
    scanf("%f",&A[i][j]);
    //#ifdef DEBUG
    printf("%f \n",A[i][j]);
    //#endif
  }
}

No sé muy bien qué hace el #ifdef DEBUG, pero es lo que hay y no molesta.

Entonces mi plan es que haga que el usuario introduzca los elementos de la matriz y, si no cumple la condición del while, entonces vuelve a pedir que los introduzca.

La condición de que la matriz no sea simétrica (y por tanto vuelva a repetir el input) es:

Code: Select all

for(i=0;i<N;i++)

  for(j=0;j<N;j++)
  {
    A[i][j]!=A[j][i];
  }
}


Por tanto, utilizando la estructura do-while y según mi lógica, quedaría algo así:

Code: Select all

do
{
  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      printf("\nelemento [%d][%d]= ",i,j);
      scanf("%f",&A[i][j]);
      //#ifdef DEBUG
      printf("%f \n",A[i][j]);
      //#endif
    }
  }
}
while
(
  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      A[i][j]!=A[j][i];
    }
  }
);


Esto al compilador no le mola y me imagino que a la gente que entiende de C/C++ tampoco. ¿No puedo introducir un bucle en la condición del while? Porque claro, yo quiero que revise la condición para todos los elementos A[i][j].

Otra opción es decirle en el propio input que compruebe si el elemento A[j][i] es igual que el elemento A[i][j] para todos los elementos con j>i (porque si no, lo comprobaría con las primeras entradas y otras que aún no hemos introducido). Sin embargo, yo creo que esto es más sucio y complicado.

¡Muchas gracias!

User avatar
Pappapishu
Compañero de fatigas
Compañero de fatigas
Posts: 11986
Joined: 31 Jan 2010, 10:43
PSN ID: Pappaìshu
Twitter: @Pappapishu
STEAM: pappapishu
Location: Puerto Pollo, Isla Plunder
Contact:

Re: Duda rápida de C++: do... while...

Post by Pappapishu » 26 May 2011, 18:59

Esta claro cual es el problema sin profundizar mucho en el código. Mira:

do
{
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
printf("\nelemento [%d][%d]= ",i,j);
scanf("%f",&A[i][j]);
//#ifdef DEBUG
printf("%f \n",A[i][j]);
//#endif
}
}
}
while
(
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
A[i][j]!=A[j][i];
}
}
);

No puedes meter un for dentro de una condición. Si entrar a valorar el resultado que te de deberías hacer algo en plan usar una variable así:

Esta claro cual es el problema sin profundizar mucho en el código. Mira:

Code: Select all

declaras variables = true;//supongo que quieres que de vueltas mientras sea traspuesta.

do
{
  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      printf("\nelemento [%d][%d]= ",i,j);
      scanf("%f",&A[i][j]);
      //#ifdef DEBUG
      printf("%f \n",A[i][j]);
      //#endif
    }
  }

//pones aquí el for ese que comprueba si es traspuesta, que también estaba mal puesto que no hacía nada, solo comprobaba que fuera disinto pero no lo cambiaba

for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
//en el momento que no se cumpla esto, no es traspuesta y por tanto pones la variables a false para que no repita el bucle
      if(A[i][j]!=A[j][i]){
        variable = false;
      }

    }
  }
}
while(variable == true);



No sé si será lo que buscas, pero probablemente compile y se acerque a ello!
Image
https://www.instagram.com/madridwolvesqt/

User avatar
will-o-the-wisp
Panacea Definitiva
Panacea Definitiva
Posts: 2466
Joined: 20 Dec 2009, 14:00
PSN ID: oh_mike_dog
Twitter: @oh_mike_god
Location: Zaragoza

Re: Duda rápida de C++: do... while...

Post by will-o-the-wisp » 26 May 2011, 19:13

¿Pero con la estructura do-while no ejecuta y luego comprueba? Es decir, lo que yo he escrito debería hacer lo siguiente:
1) (Do) Pide elementos de la matriz.
2) (While) Comprueba si no es simétrica. No tiene que cambiar nada (lo hace el usuario en el siguiente paso).
3) Si no es simétrica, se cumple la condición y vuelve a hacer el contenido del do. Si es simétrica, la condición del while no se cumple y sigue el programa porque estaba bien.

Es decir, sería lo que has puesto, solo que con la variable al revés:

Code: Select all

do
{
  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      printf("\nelemento [%d][%d]= ",i,j);
      scanf("%f",&A[i][j]);
      //#ifdef DEBUG
      printf("%f \n",A[i][j]);
      //#endif
    }
  }

  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      A[i][j]!=A[j][i];
      variable=true;
    }
  }
}
while (variable==true);


Ahora lo pruebo. Al principio pensaba que no iba a funcionar porque el elemento A[N][N] (el último en el que haría la comprobación) es inevitablemente igual que A[N][N] y daría a variable el valor false (por lo que no se repetiría el bucle aunque tuviera entradas no simétricas), pero en realidad no hemos puesto la condición de que cuando se cumpla dé valor false. Por tanto, cuando hay un error, cambia la variable para el resto de la comprobación.

User avatar
Pappapishu
Compañero de fatigas
Compañero de fatigas
Posts: 11986
Joined: 31 Jan 2010, 10:43
PSN ID: Pappaìshu
Twitter: @Pappapishu
STEAM: pappapishu
Location: Puerto Pollo, Isla Plunder
Contact:

Re: Duda rápida de C++: do... while...

Post by Pappapishu » 26 May 2011, 19:17

Code: Select all

Se te ha olvidado poner el if dentro:

    for(j=0;j<N;j++)
    {
      if(A[i][j]!=A[j][i])
      variable=true;
    }



Si no está comparando eso pero no hace nada al respecto, con el if solo lo pone a true al cumplor la condicion
Image
https://www.instagram.com/madridwolvesqt/

User avatar
Inferno
Amigo De Ultros
Amigo De Ultros
Posts: 5420
Joined: 07 Sep 2009, 01:45
PSN ID: Blackvals
Location: Vic

Re: Duda rápida de C++: do... while...

Post by Inferno » 26 May 2011, 19:20

Una de las cosas que no entiendo es por qué si estás con C++ usas printf / scanf en lugar de cout / cin xD.
A ver, tu lo que quieres creo que es al revés de lo que dice Papp, que mientras no sean todos iguales vuelves a dentro.
El código de Papp sería correcto sólo que por ejemplo teniendo un booleano no te hace falta comparar con true o false, y excepto que es al revés xD.
Lo que podrías hacer también es cuando miras que sea simétrica, en vez de hacerlo con for, hacerlo con 2 while para poder salir una vez detectes que no lo es, pero eso ya es más depurar el código.

User avatar
will-o-the-wisp
Panacea Definitiva
Panacea Definitiva
Posts: 2466
Joined: 20 Dec 2009, 14:00
PSN ID: oh_mike_dog
Twitter: @oh_mike_god
Location: Zaragoza

Re: Duda rápida de C++: do... while...

Post by will-o-the-wisp » 26 May 2011, 19:22

Ostras, de hecho me pedía introducir la matriz todo el rato xDD

Code: Select all

do
{
  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      printf("\nelemento [%d][%d]= ",i,j);
      scanf("%f",&A[i][j]);
      //#ifdef DEBUG
      printf("%f \n",A[i][j]);
      //#endif
    }
  }

  for(i=0;i<N;i++)
  { 
    for(j=0;j<N;j++)
    {
      if(A[i][j]!=A[j][i])
      variable=1;
    }
  }
}
while (variable==1);


He cambiado el false por 0 y el true por 1 porque no sabía cómo definir una variable booleana. Así ya funciona bien. ¡Muchas gracias! : D

User avatar
Inferno
Amigo De Ultros
Amigo De Ultros
Posts: 5420
Joined: 07 Sep 2009, 01:45
PSN ID: Blackvals
Location: Vic

Re: Duda rápida de C++: do... while...

Post by Inferno » 26 May 2011, 19:26

¿Seguro que no programas en C en lugar de en C++? xD

User avatar
will-o-the-wisp
Panacea Definitiva
Panacea Definitiva
Posts: 2466
Joined: 20 Dec 2009, 14:00
PSN ID: oh_mike_dog
Twitter: @oh_mike_god
Location: Zaragoza

Re: Duda rápida de C++: do... while...

Post by will-o-the-wisp » 26 May 2011, 19:30

Este código estrictamente está en C, pero en la asignatura de Programación del primer cuatrimestre hacíamos C++, así que programamos en uno o en otro según les apetece. Aún así realmente la única diferencia que he visto ha sido cambiar los cin y cout por scanf y printf. Sé que los booleanos se utilizan en C++, pero realmente no hemos llegado a usarlos nunca (y, esencialmente, no hay mucha diferencia con utilizar enteros y definir algo como 0 y algo como 1).

User avatar
Black Flare
Plumaje Fénix
Plumaje Fénix
Posts: 796
Joined: 18 Jan 2010, 13:35
Location: Pitágoras.

Re: Duda rápida de C++: do... while...

Post by Black Flare » 26 May 2011, 19:38

Eso me suena más a C que a C++, pero bueno xDD. ¿Y por que no haces que el usuario introduzca directamente una matriz simétrica en vez de comprobar que lo es? Si se puede cambiar el código con el que introduces los datos, podrías hacer que el usuario nunca pudiera equivocarse al escribir la matriz. ¡ojo!, sólo si quieres que introduzca SOLO matrices simétricas.

Code: Select all

for (int i = 0; i < N; i++) {
   for (int j = i; j < N; j++) {
      printf("\nelemento [%d][%d]= ",i,j);
      scanf("%f",&A[i][j]);
      scanf("%f",&A[j][i]);
      //#ifdef DEBUG
      printf("%f \n",A[i][j]);
      //#endif
   }
}


Así te ahorras el coste de tener que comprobar si la matriz es simétrica, pero como te he dicho esto hace que sólo puedas introducir ese tipo de matrices, si debes poder hacer cualquier tipo entonces tendrás que hacer la comprobación como dice Papp, una vez que termines de introducir los valores realizar un doble bucle para comprobar los valores.

Vamos, incluso puedes usar la misma técnica para lo que dice Papp

Code: Select all

for(i=0;i<N;i++) 
  { 
    for(j=i;j<N;j++)
    {
      if(A[i][j]!=A[j][i]) variable = false;
    }
  }


Incluso te ahorras la mitad del bucle (ya si lo pones con while no puedes hacer nada mejor XD)

EDIT: Y para rematar la faena, si pones el bucle para comprobar la matriz simétrica no empieces en i, sino en j = i + 1, ya que no hace falta que mires los valores en los que i == j
Image

User avatar
will-o-the-wisp
Panacea Definitiva
Panacea Definitiva
Posts: 2466
Joined: 20 Dec 2009, 14:00
PSN ID: oh_mike_dog
Twitter: @oh_mike_god
Location: Zaragoza

Re: Duda rápida de C++: do... while...

Post by will-o-the-wisp » 26 May 2011, 19:50

Sí, se me había ocurrido que solo introdujera el triángulo sobre la diagonal y que así no haya forma de equivocarse, pero como tampoco sé lo que me van a pedir... Especulando un poco, como calcula el autovalor máximo y su correspondiente autovector, y dado que los autovectores de una matriz simétrica son ortogonales, me imagino que me pedirán construir una base ortonormal y calcular los demás por el método de ortogonalización de Gram-Schmidt. Aún así, decirle al ordenador que haga eso es un poco complicado y no estoy seguro de si me compensa empezar a trabajar en ello sin saber si me lo van a pedir xDD

Pero por si acaso, me guardo el algoritmo que hace siempre matrices simétricas. ¡Muchas gracias!

EDIT: Es cierto, no hace falta que mire si la diagonal está bien xD

EDIT 2: Al final he hecho dos versiones del programa: la que comprueba si has hecho bien el input y la que lo hace bien directamente. En esta última he modificado un poco el código para que no haya que introducir el valor dos veces (he sustituido el scanf del elemento A[j][i] por una asignación).

Code: Select all

for (i = 0; i < N; i++) 
{
  for (j = i; j < N; j++)
  {
    printf("\nelemento [%d][%d]= ",i,j);
    scanf("%f",&A[i][j]);
    A[j][i]=A[i][j];
    //#ifdef DEBUG
    printf("%f \n",A[i][j]);
    //#endif
    }
}

Post Reply