Ver Mensaje Individual
  #2 (permalink)  
Antiguo 10/12/2015, 02:34
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Violación de segmento ('core' generado)

Que el programa te arroje los resultados esperados en todos los apartados menos en ese no implica necesariamente que el programa esté bien:

Código C++:
Ver original
  1. class Poli : public vector<double>

Has de saber que el destructor de std::vector<T> no es virtual. Esto quiere decir que si usas polimorfismo te puedes encontrar con la desagradable sorpresa de que no se invoca al destructor de Poli, con lo que toda la memoria reservada por este objeto o por sus variables internas se quedará en el limbo.

Código C++:
Ver original
  1. class NoVirtualA
  2. {
  3.   public:
  4.     NoVirtualA(){}
  5.  
  6.     ~NoVirtualA()
  7.     { std::cout << "NoVirtualA::~NoVirtualA()" << std::endl; }
  8. };
  9.  
  10. class NoVirtualB : public NoVirtualA
  11. {
  12.   public:
  13.     NoVirtualB(){}
  14.  
  15.     ~NoVirtualB()
  16.     { std::cout << "NoVirtualB::~NoVirtualB()" << std::endl; }
  17. };
  18.  
  19. class VirtualA
  20. {
  21.   public:
  22.     VirtualA(){}
  23.  
  24.     virtual ~VirtualA()
  25.     { std::cout << "VirtualA::~VirtualA()" << std::endl; }
  26. };
  27.  
  28. class VirtualB : public VirtualA
  29. {
  30.   public:
  31.     VirtualB(){}
  32.  
  33.     ~VirtualB()
  34.     { std::cout << "VirtualB::~VirtualB()" << std::endl; }
  35. };
  36.  
  37. int main()
  38. {
  39.   std::cout << "Caso 1: Se llama a los dos destructores:" << std::endl;
  40.   NoVirtualB* noVirtualB = new NoVirtualB;
  41.   delete noVirtualB;
  42.  
  43.   std::cout << "Caso 2: Dónde quedó el segundo destructor?" << std::endl;
  44.   NoVirtualA* noVirtualA = new NoVirtualB;
  45.   delete noVirtualA;
  46.  
  47.   std::cout << "Caso 3: Ahora si aparecen los dos destructores:" << std::endl;
  48.   VirtualA* virtualA = new VirtualB;
  49.   delete virtualA;
  50. }

Lo suyo, más que herencia, sería tirar de composición, es decir, hacer que el vector fuese un miembro de Poli. Claro está te obligaría a implementar métodos para añadir, eliminar, acceder y modificar los diferentes monomios pero el diseño no sería problemático.

Otro error que tienes es la comparación de datos de tipo double:

Código C++:
Ver original
  1. int Poli::Gr() const
  2. {
  3.    int gr= 0;
  4.    for (int k=0; k < (*this).size(); k++)
  5.       if ( (*this)[k] != 0.0 )
  6.           gr= k;
  7.    return gr;
  8. }

Si te han explicado las cosas por orden, habrás tenido que ver cómo se almacenan los números decimales en la memoria del ordenador (eso de la mantisa, el exponente, ...). Así mismo habrás visto que un número decimal no tiene por qué tener una representación exacta en binario. Hay números muy tontos como, por ejemplo, 0,3 que en binario tendrá infinitos dígitos: 0.01010101... queda claro entonces que por mucho que te esfuerces no vas a poder almacenar exactamente 0,3 en 32 bits (o 64 o los que te de la gana).

La forma correcta de comparar decimales es asumir que dos números son iguales si se parecen lo suficiente... esto es |A - B| < ALGO. Normalmente ALGO puedes sustituirlo por 1e-4 o 1e-6... si usas double puedes aumentar la precisión pero normalmente no te va a aportar gran cosa. Por cierto, nota que me estoy quedando con el valor absoluto de la resta.

Más cosillas:

Código C++:
Ver original
  1. int Poli::Gr() const
  2. {
  3.    int gr= 0;
  4.    for (int k=0; k < (*this).size(); k++)
  5.       if ( (*this)[k] != 0.0 )
  6.           gr= k;
  7.    return gr;
  8. }

Si en el vector almacenas en la posición 0 el monomio menos representativo y de ahí en orden hacia arriba... por qué fuerzas al código a recorrer todo el polinomio desde el principio si lo único que te interesa es el último valor?? Funcionar funciona, pero la forma de hacerlo no es desde luego la más adecuada. Lo suyo sería empezar desde el final y quedarse con el primer valor distinto de 0... después de eso salir del bucle porque no tiene sentido seguir comprobando valores.


Seguimos:

Código C++:
Ver original
  1. Poli Residuo(Poli p, Poli q)
  2. {
  3.   Poli a, b, c, r, t;
  4.   Poli s;
  5.   s.push_back(0);
  6.     double f[q.Gr()-p.Gr()];
  7.     for(int i=0; i<=q.Gr()-p.Gr(); i++)
  8.       f[i]=0;
  9.     f[q.Gr()-p.Gr()]=q[q.Gr()]/p[p.Gr()];
  10.     for(int j=0; j<=q.Gr()-p.Gr(); j++)
  11.       a.push_back(f[j]);
  12.     b=Mult(p, a);
  13.     s = Suma(s, a);
  14.     c=Resta(q, b);
  15.   return c;
  16. }

En la función anterior centrémonos en la línea:

Código C++:
Ver original
  1. double f[q.Gr()-p.Gr()];

¿Qué sucede si p.Gr() es mayor que q.Gr()? Se puede crear un array con tamaño negativo? la respuesta rápida es que no. ¿Es muy importante esto? pse... si miramos otra función:

Código C++:
Ver original
  1. Poli MCD(Poli p, Poli q)
  2. {
  3.   Poli m;
  4.   do
  5.     {
  6.       m= Residuo(p, q); // <<<--- AQUI!!!
  7.       q = p;
  8.       p = m;
  9.     }
  10.   while(m.Gr() != 0);
  11.   return m;
  12. }

Pues lo mismo empieza a tener sentido el error que comentas :)

Y ya como bonus un pequeño detalle. Pasar a una función objetos por valor implica hacer una copia de los mismos. Para lo que estás haciendo ahora mismo no es significativo, pero es una mala práctica porque reduce muchísimo el rendimiento. Lo más común es pasar los objetos como referencias constantes, lo que evita crear una copia en cada llamada:

Código C++:
Ver original
  1. Poli MCD(const Poli& p, const Poli& q)

Lo bueno de aplicar esta solución es que no tienes que modificar para nada el código de la función!!!

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.