Universidad de Costa Rica

 

 

 

Ciencias de la Computación e Informática

 

 

Curso:

Programación II

 

 

 

Documentación

IV Tarea Programada

 

 

 

Profesor: Adolfo Di-Mare

 

 

 

Alumnos:

Elsie Castro Villalobos A41369

Armando Soto Rodríguez A55609

 

 

 

 

20/09/2007

 

Índice

 

 

Introducción: 3

Dirección Internet en dónde está la documentación: 3

Descripción del problema a resolver: 3

Objetivos: 3

Abstracción: 4

Especificación de la clase Decimal: 4

Operaciones / métodos: 4

Especificación de las clases de prueba: 6

Especificación del programa: 7

Arquitectura del programa: 7

Implementación. 7

Invariante de la clase Decimal: 7

Compilador usado. 7

¿Cómo compilar el programa?. 7

Arquitectura del programa: 8

Guía de uso del programa. 9

Datos de prueba del programa. 9

Formato de los datos de prueba. 9

Entradas vs Salidas esperadas: 10

Código Fuente. 11

ADH_test.h. 11

BigNum.h. 21

decimal.h. 22

LDoble.h. 28

racional.h. 30

BigNum.cpp. 42

LDoble.cpp. 55

test_rational.cpp. 58

Bibliografía: 62

 

 

 

 

 

 

Introducción:

 

          El siguiente trabajo se basa en la implementación de una nueva clase llamada Decimal, en la cual se pondrá en práctica la reutilización de código. Esta clase deberá contar al menos con los operadores básicos esenciales los cuales son: suma, resta, multiplicación, división y modulo, para que así pueda funcionar con la clase test_rational.

    

 

Dirección Internet en dónde está la documentación:

http://www.geocities.com/elsiecv21/Documentacion4.htm

http://www.geocities.com/arsoro1986/Tarea4.htm

 

 

Descripción del problema a resolver:

 

Implementar la clase Decimal que cuenta con las operaciones aritméticas necesarias para que funcione correctamente con el programa de prueba para la clase emplantillada de números racionales. En el Rep de la clase Decimal usar una representación de los dígitos decimales lo cual permita almacenar tantos dígitos como sea necesario.

 

Objetivos:

          El objetivo de esta tarea es la de reutilización de código, y teniendo este como base implementar una nueva clase, con el fin de ahorrar tiempo y hacer más fácil la implementación de un programa.

 

 

 

 

 

Abstracción:

  Especificación de la clase Decimal:

 

       La clase decimal sirve para almacenar enteros de cualquier tamaño y así poder realizar operaciones matemáticas básicas con los mismos; suma, resta multiplicación, división y modulo.

       Para implementarla se reutilizó la clase BigNum y así poder realizar fácilmente los operadores aritméticos y los operadores de comparación.

 

 

Operaciones / métodos:

 

Clase Rational:

 

void set(INT num=0, INT den=1)   Le cambia el valor a  *this

 

INT num() const { return m_num; }   Copia del numerador

INT den() const { return m_den; }   Copia del denominador

 

rational& operator  = (const rational&):   Asignación de copia; copia desde "o", el valor anterior de "*this" se pierde.

 

rational& operator  = (INT): Asignación desde un "long".

rational& swap ( rational& ): Intercambia los valores de "*this" y "o".

 

rational& operator += (const rational&): Le suma a "*this" el valor de "otro".

rational& operator -= (const rational&): Le resta a "*this" el valor de "otro".

rational& operator *= (const rational&): Multiplica "*this" por "num".

rational& operator /= (const rational&): Divide "*this" por el valor de "num".

 

 

rational operator  - () const: Calcula y retorna el valor "-x".

friend rational<T> operator + (const rational<T>&, const rational<T>&): Calcula y retorna la suma "x+y".

 

friend rational<T> operator - (const rational<T>&, const rational<T>&): Calcula y retorna la resta "x-y".

   

friend rational<T> operator * (const rational<T>&, const rational<T>&): Calcula y retorna la multiplicación "x*y".

   

friend rational<T> operator / (const rational<T>&, const rational<T>&): Calcula y retorna la división "x/y".

 

   

friend bool operator == (const rational<T>&, const rational<T>&): compara dos numeros racionales x == y

     

friend bool operator <  (const rational<T>&, const rational<T>&):

compara si un racional es menor a otro x < y

 

friend bool operator != (const rational<T>&, const rational<T>&):

compara si un racional es disferente de otro x != y

     

friend bool operator <= (const rational<T>&, const rational<T>&):

compara si un racional es menor o igual a otro x <= y

     

friend bool operator >= (const rational<T>&, const rational<T>&):

compara si un racional es mayor o igual a otro x >= y

 

friend bool operator >  (const rational<T>&, const rational<T>&):

compara si un racional es mayor a otro x > y

     

friend ostream& operator << (ostream &, const rational<T>& ): Graba el valor de "r" en el flujo "COUT".

     

friend istream& operator >> (istream &, rational<T>& ): Lee del flujo de texto "CIN" el valor de "r".

rational& fromString (const char* nStr): Establece el varlor de "*this" a partir de la hilera "nStr".

     

friend double real   (const rational<T>& ): Conversión a real.

     

friend INT   integer(const rational<T>& ): Conversión a long.

 

     

friend bool check_ok( const rational<T>& r ): Revisa la invariante.

 

 

Clase Decimal:

 

bool operator== (const decimal &x, const decimal &y)  ¿ x == y ?


bool operator< (const decimal &x, const decimal &y)  ¿ x < y ?


bool operator> (const decimal &x, const decimal &y)  ¿ x > y ?


bool operator!= (const decimal &x, const decimal &y)  ¿ x != y ?


bool operator<= (const decimal &x, const decimal &y)  ¿ x <= y ?


bool operator>= (const decimal &x, const decimal &y)  ¿ x >= y ?


ostreamoperator<< (ostream &COUT, const decimal &r)  Graba el valor de
"r" en el flujo "COUT".


istreamoperator>> (istream &CIN, decimal &r)  Lee del flujo de texto
"CIN" el valor de "r".


decimal operator+ (const decimal &x, const decimal &y)  
"x+y".


decimal operator- (const decimal &x, const decimal &y)  
"x-y". - Calcula y retorna la resta "x-y".


decimal operator * (const decimal &x, const decimal &y)  
"x*y".


decimal operator/ (const decimal &x, const decimal &y)  
"x/y".


decimal operator% (const decimal &x, const decimal &y)

 

 

 

   Especificación de las clases de prueba:

 

bool run () : Función principal del la prueba - Requiere que recién haya sido ejecutado setUp().

virtual void setUp (): Establece el ambiente de prueba.

bool Run (): Sinónimo de run().

bool runTest (): Sinónimo de run().

int nPass () const:  Cantidad de pruebas exitosas.

int nError () const: Cantidad de pruebas que han fallado.

void recordSuccess (): Registra como exitoso el resultado de una prueba.

virtual void reset (): Anula los contadores de pruebas.

int countTestCases () const:  Cantidad de pruebas realizadas.

std::string getName () const:  Obtiene el nombre de la prueba.

void setName (const char *name=0): Le cambia el nombre a la prueba.

const std::stringtoString () const: Hilera "enooorme" para registrar los mensajes de

pruebas fallidas, separados por "\n".

const std::stringerrorString () const: Sinónimo de toString().

virtual void tearDown (): Destruye el ambiente de prueba.

 

 

Especificación del programa:

 

            El programa realiza una serie de operaciones con numeros decimales de cualquier tamaño y asi luego realizar casos de pruebas para corroborar que los operadores matemáticos para la clase Decimal funcionen correctamente.

 

Arquitectura del programa:

 

Implementación

Invariante de la clase Decimal:

       -Ningún objeto puede estar almacenado en la posición nula.

 

Compilador usado

       C++, Visual Studio 2005

 

¿Cómo compilar el programa?

       Abrir el proyecto,  darle click en la opción build, ahí seleccionar build test-rational.

 

Arquitectura del programa:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

test_rational.cpp

 
 

 


 

 

 

test_rational.obj

 
                             

 

 

C++.lib

 

linker

 

 

 

 


                                  

                                    

test_rational.exe

 

 

 

 

 

 


 

 

 

 


Guía de uso del programa

       Este es un programa de prueba que realiza diversas operaciones con  números de tipo decimal. El programa se ejecuta automáticamente por lo que no es necesario ingresarle ningun dato.

 

 

 

 

 

 

 

Datos de prueba del programa

  Formato de los datos de prueba

            Los datos de prueba que se utilizaron son números racionales a base de numero decimales.

 

 

 

 

 

 

   Entradas vs Salidas esperadas:

 

 

Pruebas de la suma:

 

Entradas

Salidas

1/2 + 1/4

3/4

3/4 == 1/4 + 1/2

True

1 + 1/4

125/100

125/100 == 1/4 + 1

True

1/3 != 33/100

True

1/8 + 1/5

13/40

13/40 == 1/5 + 1/8

True

 

 

Pruebas de la resta:

 

Entradas

Salidas

1/2 - 1/4

10/40

-10/40 == 1/4 – 1/2

True

1 - 1/4

75/100

-75/100 == 1/4 - 1

True

-3/4 == 1/4 - 1

True

1/8 - 1/5

-3/40

3/40 == 1/5 – 1/8

True

 

 

Pruebas de la multiplicación:

 

Entradas

Salidas

1/2 * 1/4

10/80

10/80 == 1/4 + 1/2

True

1 * 1/4

10/40

10/40 == 1/4 * 1

True

1/3 != 33/100

True

1/8 * 1/5

1/40

1/40 == 1/5 * 1/8

True

Pruebas de la división:

 

Entradas

Salidas

(1/2) / (1/4)

4/2

(1/2) ==  (1/4) / (1/2)

True

1 / (1/4)

4

(1/4) == (1/4) / 1

True

1/3 != 33/100

True

(1/8) / (1/5)

5/8

(8/5) == (1/5) / (1/8)

True

 

 

      

Código Fuente

 

ADH_test.h

#ifndef ADH_test_h

#define ADH_test_h ///< Evita la inclusión múltiple

 

#include <string>      // class std::string

#include <sstream>     // class basic_ostringstream<T,Ch>

//#include <limits.h>    //

 

// using namespace std;

/// Definido por la biblioteca C++ estándar.

namespace std {} // Está acá para que Doxygen lo documente

 

/// Escuela de Ciencias de la Computación e Informática.

/// \see http:www.ecci.ucr.ac.cr

namespace ECCI { }

 

/// Establece el ambiente en que se realizará cada prueba.

/// - \c TestSuite<TestCase>::run() invoca los métodos

///   \c TestCase::setUp() y \c TestCase::tearDown()

///   cuando ejecuta cada prueba.

/// - Como \c TestCase::run() es un método abstracto,

///   para facilitar la programación lo usual es que el

///   programador no incluya invocaciones a

///   \c TestCase::setUp() y \c TestCase::tearDown()

///   pues es más simple dejar que lo haga

///   \c TestSuite<TestCase>::run().

/// - Por eso, si el programador cliente quiere que cada

///   prueba se ejecute luego de establecer el ambiente con

///   su \c TestFixture, lo más práctico es que agregue sus

///   pruebas a una colección de pruebas \c TestSuite.

class TestFixture {

public:

    virtual void setUp() { } ///< Establece el ambiente de prueba

    virtual void tearDown() { } ///< Destruye el ambiente de prueba

//  virtual ~TestCase() { tearDown(); } ///< Destructor

}; // TestFixture

 

/// NO IMPLEMENTADO ==> Colector genérico de resultados de prueba.

/// - No está implementado para \c ADH_test.h

/// - En \c ADH_test.h se usa una hilera \c std::string para colectar

///   todos los resultados. \see \c TestCase::toString().

/// - C++ tiene la ventaja sobre Java porque el programador puede

///   usar las macros \c __FILE__ y \c __LINE__  para registrar el

///   sitio en que se produce un error en tiempo de ejecución.

class TestResult {

    private: TestResult(); ///< Prohibe crear objetos de tipo \c TestResult.

};

 

/// NO IMPLEMENTADO ==> Clase abastracta para ejecutar las pruebas y recolectar los resultados.

/// - No está implementado para \c ADH_test.h

/// - En \c ADH_test.h se usa una hilera \c std::string para colectar

///   todos los resultados. \see \c TestCase::toString().

class Test {

private: Test(); ///< Prohibe crear objetos de tipo \c Test.

public:

    /// Retorna la cantidad de pruebas a realizar

    virtual int countTestCases() = 0;

    /// Ejecuta la prueba y recolecta sus resultados en \c result

    virtual void run(TestResult& result) = 0;

};

 

#include <typeinfo.h>  // class std::type_info ==> char* typeid().name();

 

/// Cada caso de prueba es una instancia derivada de esta clase abstracta.

/// - Siempre es obligatorio implementar \c TestCase::run().

class TestCase : public TestFixture {

protected:

    int m_pass; ///< Cantidad de pruebas exitosas

    int m_error; ///< Cantidad de pruebas que han fallado

    const char * m_name; ///< Nombre del caso de prueba

    /// Hilera "enooorme" para registrar los mensajes de pruebas fallidas, separados por \c "\n"

    std::string m_errorString;

public:

    TestCase(const char * name=0);

    virtual ~TestCase() { }  ///< Destructor

    virtual bool run() = 0; ///< Ejecuta la prueba y retorna \c "false" si falla

    bool Run()        { return run(); } ///< Sinónimo de \c run()

    bool runTest()    { return run(); } ///< Sinónimo de \c run()

    int nPass() const { return m_pass; } ///< Cantidad de pruebas exitosas

    int nError() const { return m_error; } ///< Cantidad de pruebas que han fallado

    void recordSuccess() { ++m_pass; } ///< Registra como exitoso el resultado de una prueba

    virtual void reset() { m_pass =  m_error = 0; m_errorString = ""; } ///< Anula los contadores de pruebas

public:

    int countTestCases() const { return nPass()+nError(); } ///< Cantidad de pruebas realizadas

    /// Obtiene el nombre de la prueba

    std::string getName() const { return ( m_name != 0 ? m_name : typeid(*this).name()); }

    void setName( const char * name=0 ) { m_name = name; } ///< Le cambia el nombre a la prueba

    /// Hilera "enooorme" para registrar los mensajes de pruebas fallidas, separados por \c "\n"

    const std::string& toString() const { return m_errorString; }

    const std::string& errorString() const { return toString(); } ///< Sinónimo de \c toString()

protected:

    void recordError( const std::string& lbl, const char* fname, int lineno);

    void testThis( bool cond, const std::string& lbl, const char* fname, long lineno);

    void testThis( bool cond, const char*        lbl, const char* fname, long lineno) {

         testThis( cond, std::string(lbl), fname, lineno);

    } ///< Sinónimo de \c testThis()

private:

    TestCase(const TestCase&);            ///< \c "private" evita la copia de casos de prueba

    TestCase& operator=(const TestCase&); ///< \c "private" evita la copia de casos de prueba

}; // TestCase

 

/// NO IMPLEMENTADO ==> Colección de pruebas.

class TestSuite : public TestCase { };

 

inline TestCase::TestCase(const char * name) : m_pass(0), m_error(0), m_name(name), m_errorString() {

    m_errorString = "";

}  ///< Constructor

 

/** Efectúa la prueba y registra el resultado.

    - Si la prueba es exitosa sólo incrementa la cantidad de éxitos \c nPass().

    - Si la prueba falla reporta en \c toString()   el hecho.

    - La prueba es \c "cond".

    - Los valores \c "fname" y \c "lineno" indican el archivo y el renglón

      en donde se ejecuta la prueba.

    - Usualmente los valores de \c "fname" y \c "lineno" se obtienen con

      las macros globales \c "__FILE__" y \c "__LINE__".

 

    Este método es invocado usando la macro homónima \c TEST_THIS()  */

inline void TestCase::testThis( bool cond, const std::string& lbl, const char* fname, long lineno) {

    if (cond) {

        recordSuccess();

    }

    else {

        recordError(lbl, fname, lineno);

    }

}

 

/** Registra la falla de la prueba y luego lo acumula en la hilera de fallas \c toString().

    - Los valores \c "fname" y \c "lineno" indican el archivo y el renglón

      en donde se ejecuta la prueba.

    - Usualmente los valores de \c "fname" y \c "lineno" se obtienen con

      las macros globales \c "__FILE__" y \c "__LINE__".

 

    Este método es invocado usando la macro \c TEST_ERROR() */

inline void TestCase::recordError( const std::string& lbl, const char* fname, int lineno) {

//  typedef basic_ostringstream<char> ostringstream;

    std::basic_ostringstream<char> ost; // ostringstream ost;

    ost << "=\\_error: " << lbl << " \n=/ (" << lineno << ") " << fname << "\n";

    m_errorString += ost.str();

    m_error++;

}

 

/// [ADH_test] Macros propios de \c ADH_test.h

#define TEST_ADH_test()

#undef  TEST_ADH_test

 

/// [ADH_test] Efectúa la prueba \c cond y registra el resultado.

/// - Si la prueba \c cond tiene éxito invoca el método

///   \c TestCase::recordSuccess()

/// - Si la prueba \c cond falla invoca el método

///   \c TestCase::recordFail()

/// - Esta es una una macro que invoca el método

///   \c TestCase::testThis()

///   \code

///   TEST_THIS("0 != 1"); // Siempre tiene éxito

///   testThis(0 != 1, "0 != 1", __FILE__, __LINE__ ); // Siempre tiene éxito

///   \endcode

#define TEST_THIS(cond) testThis( cond, #cond, __FILE__, __LINE__ )

 

/// [ADH_test] Macro similar a \c TEST_THIS() que usa el mensaje \c msg en caso de falla.

/// - El mensaje \c msg debe ser una hilera literal o un objeto que pueda

///   convertirse en <code>const char *</code>

#define TEST_THIS_Msg(msg, cond) testThis( cond, msg, __FILE__, __LINE__ )

 

/// [ADH_test] Registra como "error" el resultado de una prueba.

/// - El programador cliente es quien determinó que la prueba

///   falló y por eso quiere registrar ese hecho.

/// - Está implementado comun una macro que invoca

///   el método \c TestCase::recordError()

///

///   \code

///   if (22==33) {

///       TEST_ERROR("22 != 33"); // Registra que la prueba falló

///   }

///   \endcode

#define TEST_ERROR(str) recordError( str, __FILE__, __LINE__ )

 

/// [ADH_test] Registra como "exitoso" el resultado de una prueba.

/// - El programador cliente es quien determinó que la prueba

///   fue exitosa y por eso quiere registrar ese hecho.

/// - Generalmente se usa después de atrapar una excepción que

///   se supone debió ser lanzada como resultado de la prueba.

/// - Está implementado comun una macro que invoca

///   el método \c TestCase::recordSuccess()

///

///   \code

///   queue<T> Q(SIZE); // la cola "Q" está vacía ==> no tiene "front()"

///   try {

///       Q.front();  // Es incorrecto usar un valor de la cola si la cola está vacía

///       TEST_ERROR("Q.front();"); // Fallaría si "front()" no levanta la excepción

///    }

///    catch (std::logic_error&) {

///       TEST_SUCCESS(); // Esto es lo correcto pues "front()" levanta "logic_error" para unca cola vacía

///   }

///   \endcode

#define TEST_SUCCESS() recordSuccess()

 

/// [ADH_test] Efectúa la prueba para determinar si <code>expected == actual</code>.

/// - Si la prueba tiene éxito invoca el método

///   \c TestCase::recordSuccess()

/// - Si la prueba falla invoca el método

///   \c TestCase::recordFail()

/// - Esta es una una macro que invoca el método

///   \c TestCase::testThis()

#define TEST_EQUAL(expected, actual) \

        testThis( (expected) == (actual), #expected " == " #actual, __FILE__, __LINE__ )

 

/// [ADH_test] Efectúa la prueba para determinar si <code>expected == actual</code>.

/// - Si la prueba tiene éxito invoca el método

///   \c TestCase::recordSuccess()

/// - Si la prueba falla invoca el método

///   \c TestCase::recordFail()

/// - Esta es una una macro que invoca el método

///   \c TestCase::testThis()

/// - Registra el mensaje \c MSG si la prueba falla.

#define TEST_EQUAL_Msg(MSG, expected, actual) \

        testThis( (expected) == (actual), MSG, __FILE__, __LINE__ )

 

/// Operación de grabado que permite reportar el resultado de la prueba \c test.

/// - Graba en \c COUT el nombre, cantidad de éxitos y cantidad de errores.

std::ostream & operator << (std::ostream& COUT, const TestCase& test) {

    COUT << "TestCase \""  << test.getName() << "\":\n"

         << "\tOK: "       << test.nPass()

         << "\tERROR: "    << test.nError() << "\n";

    return COUT;

}

 

/// Graba en \c "COUT" el resultado de la prueba \c test.

/// - Retorna la cantidad total de errores \c test.nError().

/// - Además, graba la cantidad de pruebas exitosas y erróneas.

/// - Si hubo pruebas no exitosas, graba los mensajes de error correspondientes.

inline long Report( std::ostream& COUT, const TestCase &test ) {

    COUT << test;

    if (test.nError() != 0) {

        COUT << test.errorString();

    }

    return test.nError();

}

 

// ¿¿¿ TestSuite ???

 

//inline bool check_ok<int>( const int & )      { return true; }

//template<class unsigned> inline bool check_ok( const unsigned & ) { return true; }

//template<class int> inline bool check_ok( const long & )     { return true; }

//template<class int> inline bool check_ok( const flota   & )  { return true; }

//template<class int> inline bool check_ok( const double & )   { return true; }

 

template <class T> bool check_ok( const T& ); ///< Declaración genérica para \c check_ok()

inline bool check_ok( const signed char &   ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const unsigned char & ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const signed int &    ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const unsigned int&   ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const signed long &   ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const unsigned long & ) { return true; } ///< \c check_ok<>()

inline bool check_ok( const float &       )   { return true; } ///< \c check_ok<>()

inline bool check_ok( const double &      )   { return true; } ///< \c check_ok<>()

inline bool check_ok( const long double & )   { return true; } ///< \c check_ok<>()

 

/// Retorna una hilera que contiene el valor de \c val.

/// - \c toString() with standard C++

template <class T>

std::string toString( const T & val ) {

//  typedef basic_ostringstream<char> ostringstream;

    std::basic_ostringstream<char> temp; // ostringstream temp;

    temp << val;

    return temp.str( );

}

 

/// [CppUnit] Macros propios de \c CppUnit http://cppunit.sourceforge.net/doc/lastest

#define CPPUNIT_ADH_test()

#undef  CPPUNIT_ADH_test

 

/// [CppUnit] Assertions that a condition is true.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga0

#define CPPUNIT_ASSERT(condition) TEST_THIS(condition)

 

/// [CppUnit] Assertion with a user specified message.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga1

#define CPPUNIT_ASSERT_MESSAGE(message, condition) CPPUNIT_ASSERT(condition)

 

/// [CppUnit] Fails with the specified message.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga2

#define CPPUNIT_FAIL(message) TEST_ERROR(message)

 

/// [CppUnit] Asserts that two values are equals.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga3

#define CPPUNIT_ASSERT_EQUAL(expected, actual) TEST_EQUAL(expected, actual)

 

/// [CppUnit] Asserts that two values are equals, provides additional messafe on failure.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga4

#define CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) \

        TEST_EQUAL_Msg(message, expected, actual)

 

/// [CppUnit] Macro for primitive value comparisons.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga5

#define CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)                 \

        assertEquals_Delta(expected, actual, delta)

 

/// [CppUnit] Asserts that the given expression throws an exception of the specified type.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga6

#define CPPUNIT_ASSERT_THROW(expression, ExceptionType)  \

        do {                                             \

            bool cpputExceptionThrown_ = false;          \

            try {                                        \

                expression;                              \

            } catch ( const ExceptionType & ) {          \

                cpputExceptionThrown_ = true;            \

            }                                            \

                                                         \

            if ( cpputExceptionThrown_ ) {               \

                break;                                   \

            }                                            \

            TEST_ERROR(                                  \

                "Expected exception: " #ExceptionType )  \

        } while ( false )

 

/// [CppUnit] Asserts that the given expression does not throw any exceptions.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga7

#define CPPUNIT_ASSERT_NO_THROW(expression)                  \

        do {                                                 \

            try {                                            \

                expression;                                  \

            } catch ( ... ) {                                \

                TEST_ERROR("Unexpected exception caught");   \

            }                                                \

        } while ( false )

 

/// [CppUnit] Asserts that an assertion fail.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga8

#define CPPUNIT_ASSERT_ASSERTION_FAIL(assertion)               \

        CPPUNIT_ASSERT_THROW( assertion, CPPUNIT_NS::Exception )

 

/// [CppUnit] Asserts that an assertion pass.

/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga9

#define CPPUNIT_ASSERT_ASSERTION_PASS(assertion) \

        CPPUNIT_ASSERT_NO_THROW( assertion )

 

// /// Concatena la hilera \c THIS con la hilera \c THAT

// #define ADH_test_CAT( THIS, THAT ) (std::string(THIS) + std::string(THAT).c_str()

 

#define JUnit_ADH_test()

#undef  JUnit_ADH_test

 

/// [JUnit] Macros propios de \c JUnit http://junit.sourceforge.net/javadoc/junit/framework/Assert.html

///  Asserts that two objects are equal.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.Object,%20java.lang.Object)

#define assertEquals(          EXPECTED, ACTUAL ) TEST_EQUAL(EXPECTED, ACTUAL)

///  Asserts that two objects are equal (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.String,%20java.lang.Object,%20java.lang.Object)

#define assertEquals_Msg( MSG, EXPECTED, ACTUAL ) TEST_EQUAL_Msg(MSG, EXPECTED, ACTUAL)

 

/// [JUnit] Asserts that a condition is true.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertTrue(boolean)

#define assertTrue(           CONDITION ) testThis( CONDITION, #CONDITION, __FILE__, __LINE__ )

/// [JUnit] Asserts that a condition is true (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertTrue(java.lang.String,%20boolean)

#define assertTrue_Msg( MSG,  CONDITION ) testThis( CONDITION,  MSG,       __FILE__, __LINE__ )

 

/// [JUnit] Asserts that a condition is false.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertFalse(boolean)

#define assertFalse(          CONDITION ) testThis( !(CONDITION), "!(" #CONDITION ")", __FILE__, __LINE__ )

/// [JUnit] Asserts that a condition is false (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertFalse(java.lang.String,%20boolean)

#define assertFalse_Msg( MSG, CONDITION ) testThis( !(CONDITION),       MSG,           __FILE__, __LINE__ )

 

#include <math.h> // fabs()

/// [JUnit] Asserts that two doubles are equal concerning a delta.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(double,%20double,%20double)

#define assertEquals_Delta(EXPECTED, ACTUAL, DELTA ) \

        testThis( fabs( double(EXPECTED) -  double(ACTUAL) ) < double(DELTA), \

        "|"  #EXPECTED "-" #ACTUAL "| < " #DELTA,  __FILE__, __LINE__ )

 

/// [JUnit] Asserts that two doubles are equal concerning a delta (with message).

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.String,%20double,%20double,%20double)

#define assertEquals_Delta_Msg( MSG, EXPECTED, ACTUAL, DELTA ) \

        testThis( fabs( double(EXPECTED) -  double(ACTUAL) ) < double(DELTA), \

        MSG, __FILE__, __LINE__ )

 

/// [JUnit] Asserts that an object is null.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNull(java.lang.Object)

#define assertNull(OBJECT)    testThis( 0==&(OBJECT), "assertNull("    #OBJECT ")", __FILE__, __LINE__ )

/// [JUnit] Asserts that an object isn't null.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNotNull(java.lang.Object)

#define assertNotNull(OBJECT) testThis( 0!=&(OBJECT), "assertNotNull(" #OBJECT ")", __FILE__, __LINE__ )

 

/// [JUnit] Asserts that two objects refer to the same object.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertSame(java.lang.Object,%20java.lang.Object)

#define assertSame(THIS, THAT) testThis(    &(THIS)==&(THAT), "assertSame("    #THIS ", " #THAT ")", __FILE__, __LINE__ )

///  Asserts that two objects do not refer to the same object.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNotSame(java.lang.Object,%20java.lang.Object)

#define assertNotSame(THIS, THAT) testThis( &(THIS)!=&(THAT), "assertNotSame(" #THIS ", " #THAT ")", __FILE__, __LINE__ )

 

/// [JUnit] Fails a test with no message.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#fail()

#define fail(     )     TEST_ERROR("ERROR")

/// [JUnit] Fails a test with the given message.

/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#fail(java.lang.String)

#define fail_Msg( MSG ) TEST_ERROR(MSG)

 

#endif // ADH_test_h

 

 

 

BigNum.h

#if !defined(AFX_BIGNUM_H__54FCBDA3_D21D_11D2_9782_444553540000__INCLUDED_)

#define AFX_BIGNUM_H__54FCBDA3_D21D_11D2_9782_444553540000__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "LDoble.h"

#include <limits.h>

#include <iostream>

using namespace std;

//typedef PNDoble

const unsigned long int MAXBASE=USHRT_MAX+1;

 

class BigNum 

{

      LDoble *Lis;

      char signo;

private:

      virtual void copiar(const BigNum& a);

public:

      //Crea el número con valor 0.

      BigNum();

      //Crea el número con el valor recibido.

      BigNum(int);

      /*El vector recibido expresa el número en base 65536. Sign indica

      el signo del número (1 positivo, -1 negativo).                  */

      BigNum(unsigned short int a[],int cant,char sign);

      /*Convierte el número desde letras                                          */

      BigNum(char *s);

      /*Constructor de copia                                                              */

      BigNum(const BigNum& a);

      /*Pre : el número no es mayor que el maximo long (4294967295).

        Post: devuelve el número como long                                          */

      virtual long A_Numero();

      virtual BigNum& operator = (const BigNum & a);

      friend BigNum operator / (const BigNum & a, const BigNum & b);

      friend BigNum operator + (const BigNum & a, const BigNum & b);

      friend BigNum operator - (const BigNum & a, const BigNum & b);

      friend BigNum operator * (const BigNum & a, const BigNum & b);

      friend BigNum operator % (const BigNum & a, const BigNum & b);

      friend ostream& operator << (ostream& s, const BigNum & m);

      virtual int operator == (const BigNum & a) const;

      virtual int operator != (const BigNum & a) const;

      virtual int operator > (const BigNum & a) const;

      virtual int operator < (const BigNum & a) const;

      virtual int operator >= (const BigNum & a) const;

      virtual int operator <= (const BigNum & a) const;

      virtual BigNum& operator++();

      virtual BigNum& operator--();

      virtual BigNum& operator += (const BigNum & a);

      virtual BigNum& operator -= (const BigNum & a);

      virtual BigNum& operator *= (const BigNum & a);

      virtual BigNum& operator /= (const BigNum & a);

      virtual BigNum& operator %= (const BigNum & a);

      BigNum operator- () { return BigNum(0)-(*this); }

/*    friend BigNum& operator++(const BigNum& a);

      friend BigNum& operator--(const BigNum& a);*/

      virtual ~BigNum();

};

 

#endif // !defined(AFX_BIGNUM_H__54FCBDA3_D21D_11D2_9782_444553540000__INCLUDED_)

 

 

 

decimal.h

#ifndef decimal_h

#define decimal_h ///< Evita la inclusión múltiple

 

#include <iostream>

#include "BigNum.h"

#include  <cstdlib>

#include  <cctype>     // isdigit()

 

class decimal{

private:

    BigNum m_num; ///< Numerador

    decimal( const BigNum& res ) { m_num = res; }

 

 

public:

    // constructores

    decimal() : m_num(0) { }  ///< Constructor de vector

    decimal(long num) : m_num(num) { } ///< Constructor a partir de un valor entero

    decimal(const decimal& o)       /// Constructor de copia

        { m_num = o.m_num; }

    ~decimal() { }      ///< Destructor

 

 

//  void num(long n) { m_num=n; Simplify(); }  // FEO

//  void den(long d) { m_den= ( d!=0 ? d : m_den) ; Simplify(); }  // FEO

 

    decimal& operator  = (const decimal&);  // Asignación (copia)

    decimal& operator  = (long);

    decimal& swap ( decimal& );

 

    decimal& operator += (const decimal&);

    decimal& operator -= (const decimal&);

    decimal& operator *= (const decimal&);

    decimal& operator /= (const decimal&);

 

    decimal operator  - () const;              // menos unario

 

    friend decimal operator + (const decimal&, const decimal&);

    friend decimal operator - (const decimal&, const decimal&);

    friend decimal operator * (const decimal&, const decimal&);

    friend decimal operator / (const decimal&, const decimal&);

      friend decimal operator % (const decimal&, const decimal&);

 

    friend bool operator == (const decimal&, const decimal&);

    friend bool operator <  (const decimal&, const decimal&);

    friend bool operator != (const decimal&, const decimal&);

    friend bool operator <= (const decimal&, const decimal&);

    friend bool operator >= (const decimal&, const decimal&);

    friend bool operator >  (const decimal&, const decimal&);

 

    friend ostream& operator << (ostream &, const decimal& );

    friend istream& operator >> (istream &,       decimal& );

 

}; // rational

 

 

/** Copia desde \c "o".

    - El valor anterior de \c "*this" se pierde.

    \par Complejidad:

         O( \c 1 )

    \returns *this

    \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05

*/

inline decimal& decimal::operator = (const decimal& o) {

    m_num = o.m_num;

  

//  sobra invocar a "Simplify()" pues "o" ya está simplificado

    return *this;

}  // operator =

 

/** Intercambia los valores de \c "*this" y \c "o".

      \par Complejidad:

         O( \c 1 )

 

    \returns *this

 

    \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08

*/

inline decimal& decimal::swap ( decimal& o ) {

    #if 1

        decimal tmp = o;

        o = *this;

        *this = tmp;

    #else

        // Esto NO funciona para objetos, métodos virtuales, etc.

        char tmp[ sizeof( *this ) ];

        memcpy( tmp,   o,     sizeof( *this ) ); // tmp = o;

        memcpy( o,    *this,  sizeof( *this ) ); // o = *this;

        memcpy( *this, tmp,   sizeof( *this ) ); // *this = tmp;

    #endif

    return *this;

}

 

/// Asignación desde un \c "long".

inline decimal& decimal::operator = (long entero) {

    m_num = entero;

    return *this;

}  // operator =

 

/// Multiplica \c "*this" por \c "num".

inline decimal& decimal::operator *= (const decimal& num) {

    BigNum m_res;

 

      m_res = m_num * num.m_num;

      m_num = m_res;

 

    return *this;

}  // operator *=

 

/**  Divide \c "*this" por el valor de \c "num".

    \pre

    - (num != 0)

*/

inline decimal& decimal::operator /= (const decimal& num) {//lo cambiamos

    BigNum m_res;

 

      m_res = m_num / num.m_num;

      m_num = m_res;

 

    return *this;

}  // operator /=

 

/// \c "-x".

/// - Menos unario

/// - Calcula y retorna el valor \c "-x"

inline decimal decimal::operator - () const {

    decimal tmp = (*this);  // tmp.rational( *this );

    tmp.m_num = - tmp.m_num;

    return tmp;

}  // operator -

 

/// ¿ x == y ?

inline bool operator == (const decimal &x, const decimal &y) {

    return (x.m_num == y.m_num);

 

}  // operator ==

 

/// ¿ x < y ?

 

inline bool operator < (const decimal &x, const decimal &y) {

    return x.m_num < y.m_num;

 

}  // operator <

 

/// ¿ x > y ?

inline bool operator > (const decimal &x, const decimal &y) {

    return (y < x);

}  // operator >

 

/// ¿ x != y ?

inline bool operator != (const decimal& x, const decimal& y) {

    return !(x == y);

}  // operator !=

 

/// ¿ x <= y ?

inline bool operator <= (const decimal& x, const decimal& y) {

    return !(y < x);

}  // operator <=

 

/// ¿ x >= y ?

inline bool operator >= (const decimal& x, const decimal& y) {

    return !(x < y);

}  // operator >=

 

 

// EOF: rational.h

 

 

/// Le suma a \c "*this" el valor de \c "otro".

decimal& decimal::operator += (const decimal& otro) {

    BigNum m_res;

 

      m_res = m_num + otro.m_num;

      m_num = m_res;

 

    return *this;

}  // operator +=

 

 

/// Le resta a \c "*this" el valor de \c "otro".

decimal& decimal::operator -= (const decimal& otro) {

    BigNum m_res;

 

      m_res = m_num - otro.m_num;

      m_num = m_res;

 

    return *this;

}  // operator -=

 

 

/** Graba el valor de \c "r" en el flujo \c "COUT".

    - Graba el valor en el formato [num/den].

    - En particular, este es el operador que se invoca

      cuando se usa, por ejemplo, este tipo de instrucción:

     \code

          cout << r << q;

     \endcode

*/

ostream& operator<< (ostream &COUT, const decimal& r) {

  

        return COUT << "[" << r.m_num << "]" ;

 

}  // operator <<

 

/** Lee del flujo de texto \c "CIN" el valor de \c "r".

    \pre

    El número rational debe haber sido escrito usando

    el formato "[r/den]", aunque es permisible usar

    algunos blancos.

    - Se termina de leer el valor sólo cuando encuentra \c "]".

    - <code> [ -+-+-+-+- 4 / -- -+ -- 32  ] </code> se lee como

      <code> [1/8] </code>

*/

istream& operator >> (istream &CIN, decimal& r) {

    /*char ch;  // valor leido, letra por letra, de "CIN"

 

    bool es_positivo = true;    // manejo de los signos + y -

 

    // se brinca todo hasta el primer dígito

    do {

        CIN >> ch;

        if (ch == '-') {  // cambia de signo

            es_positivo = !es_positivo;

        }

    } while (!isdigit(ch));

 

    // se traga el numerador

    r.m_num = 0;

    while (isdigit(ch)) { // convierte a decimal: izq --> der

        r.m_num = 10 * r.m_num + (ch-'0');

        CIN >> ch;

    }

 

    // se brinca los blancos después del numerador

    while (isspace(ch)) {

        CIN >> ch;

    }

 

    if (ch ==']') { // es un número entero

        r.m_den = 1;

    }

    else {

        do {  // se brinca todo hasta el denominador

            CIN >> ch;

            if (ch == '-') {

                es_positivo = !es_positivo;

            }

        } while (!isdigit(ch));

 

        // se traga el denominador

        r.m_den = 0;

        while (isdigit(ch)) {

            r.m_den = 10 * r.m_den + (ch-'0');

            CIN >> ch;

        }

 

        // El programa se duerme si en el flujo de entrada

        // NO aparece el caracter delimitador final "]",

        // pues la lectura termina hasta encontrar el "]".

        while (ch != ']') {

            CIN >> ch;

        }

    }   // corrección: Andrés Arias <[email protected]>

 

 

    // le cambia el signo, si hace falta

    if (! es_positivo) {

        r.m_num = -r.m_num;

    }

 

    return CIN;

 

*/

      return CIN;

 

}  // operator >>

 

/// \c "x+y".

/// - Calcula y retorna la suma \c "x+y".

decimal operator + (const decimal &x, const decimal &y) {

 

    return decimal(x.m_num + y.m_num);

}  // operator + ()

 

/// \c "x-y".

 

/// - Calcula y retorna la resta \c "x-y".

decimal operator - (const decimal &x, const decimal &y) {

   

      return decimal(x.m_num - y.m_num);

}  // operator - ()

 

/// \c "x*y".

/// - Calcula y retorna la multiplicación \c "x*y".

decimal operator * (const decimal &x, const decimal &y) {

 

    return decimal(x.m_num * y.m_num);

}  // operator * ()

 

/// \c "x/y".

/// - Calcula y retorna la división \c "x/y".

/// \pre <code> y != 0 </code>

decimal operator / (const decimal &x, const decimal &y) {

   

    return decimal(x.m_num / y.m_num);

}  // operator / ()

 

decimal operator % (const decimal &x, const decimal &y) {

   

    return decimal(x.m_num % y.m_num);

}  // operator / ()

 

#endif // rational_h

 

LDoble.h

 

#ifndef  LDoble_h

#define  LDoble_h

 

typedef unsigned short int TDato;

typedef unsigned long int TMayor;

 

/// Nodo de la lista.

class NDoble {

public:

    TDato Dato; ///< Valor almacenado.

    NDoble *Sig,*Ant; ///< Punteros de la lista doblemente enlazada.

 

public:

    NDoble(TDato dato=0) : Dato(Dato), Sig(0), Ant(0) { }

    virtual ~NDoble() { }

};

 

#define TRUE 1

#define FALSE 0

 

typedef int Boolean;

typedef NDoble* PNDoble;

 

/// Lista doblemente enlazada.

class LDoble {

      PNDoble Prim,Ult;  /*,*Cte*/

      int CantNodos;

public:

      int CantRefs;

      LDoble();

      //Post: devuelve TRUE si no tiene elementos, sino FALSE.

      virtual Boolean Vacia();

      //Post: Elimina todos los elementos de la lista y libera la memoria.

      virtual void Vaciar();

      /*Post: inserta el elemento dat en la posición anterior al corriente.

              si la lista estaba vacía lo inserta en el primer lugar. dat

              es el nuevo corriente.                                    */

      virtual int InsAntes(PNDoble& Cte, TDato dat);

      /*Post: inserta el elemento dat en la posición posterior al corriente.

              si la lista estaba vacía lo inserta en el primer lugar. dat

              es el nuevo corriente.                                    */

      virtual int InsDespues(PNDoble& Cte, TDato dat);

      /* direccion indica adonde se mueve el corriente. Valores posibles:

         'p' (primer elemento), 's' (elemento siguiente), 'a' (elem. anterior),

         'u' (último elemento).                                                           */

      virtual int MoverCte(PNDoble& Cte, char direccion);

      /*Pre : La lista no está vacía.

        Post: Devuelve el valor del Corriente.                          */

      virtual TDato ObtCte(PNDoble Cte);

      /*Pre : La lista no está vacía.

        Post: Modifica el valor del elemento Corriente, asignandole dat.

                  Si existe el corriente devuelve 0.                        */

      virtual int ModifCte(PNDoble& Cte, TDato dat);

      /*Pre : La lista no está vacía.

        Post: Elimina el elemento actual (Corriente). El corriente es el

            siguiente. Si era el último es el anterior.                */

      virtual int ElimCte(PNDoble& Cte);

      /*Post: Devuelve la cantidad de elementos guardados en la lista.  */

      virtual int CantElem();

      /* Destructor: libera todo el espacio ocupado por la lista        */

      virtual ~LDoble();

};

 

#endif

 

racional.h

 

#ifndef rational_h

#define rational_h ///< Evita la inclusión múltiple

 

#include <iostream>

using namespace std;

 

/**  La clase \c rational implementa las operaciones aritméticas

     principales para números rationales.

     - <code> [1/3] == [2/6] ==  ...   [9/27] == ... </code>

     - <code> [1/3]  * [2/6] / [3/9] - [9/27] </code>

*/

template <class INT>

class rational {

private:

    INT m_num; ///< Numerador

    INT m_den; ///< Denominador

 

    void Simplify();

 

public:

    // constructores

    rational() : m_num(0), m_den(1) { }  ///< Constructor de vector

    rational(INT num) : m_num(num), m_den(1) { } ///< Constructor a partir de un valor entero

    rational(INT num, INT den)

        : m_num(num), m_den(den) { Simplify(); } ///< Constructor a partir de un valor quedbrado

    rational(const rational& o)       /// Constructor de copia

        { m_num = o.m_num, m_den = o.m_den; }

    ~rational() { }      ///< Destructor

 

    void set(INT num=0, INT den=1);  // Le cambia el valor a \c "*this"

 

    INT num() const { return m_num; }  ///< Copia del numerador

    INT den() const { return m_den; }  ///< Copia del denominador

 

//  void num(long n) { m_num=n; Simplify(); }  // FEO

//  void den(long d) { m_den= ( d!=0 ? d : m_den) ; Simplify(); }  // FEO

 

    rational& operator  = (const rational&);  // Asignación (copia)

    rational& operator  = (INT);

    rational& swap ( rational& );

 

    rational& operator += (const rational&);

    rational& operator -= (const rational&);

    rational& operator *= (const rational&);

    rational& operator /= (const rational&);

 

    rational operator  - () const;              // menos unario

      template <class T> friend rational<T> operator + (const rational<T>&, const rational<T>&);

      template <class T> friend rational<T> operator - (const rational<T>&, const rational<T>&);

    template <class T> friend rational<T> operator * (const rational<T>&, const rational<T>&);

    template <class T> friend rational<T> operator / (const rational<T>&, const rational<T>&);

 

    template <class T> friend bool operator == (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator <  (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator != (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator <= (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator >= (const rational<T>&, const rational<T>&);

      template <class T> friend bool operator >  (const rational<T>&, const rational<T>&);

 

      template <class T> friend ostream& operator << (ostream &, const rational<T>& );

      template <class T> friend istream& operator >> (istream &,       rational<T>& );

    rational& fromString (const char* nStr);

 

      template <class T> friend double real   (const rational<T>& );   // Conversión a real

      template <class T> friend INT   integer(const rational<T>& );   // Conversión a long

 

      template <class T> friend bool check_ok( const rational<T>& r ); // Ok()

 

}; // rational

 

template <class INT>

INT mcd(INT x, INT y); // Calcula el Máximo Común Divisor

 

/// Sinónimo de \c mcd(x,y) <code> [ inline ] </code>

template <class INT>

inline INT gcd(INT x, INT y) { return mcd(x,y); }

 

/// Cambia el valor del número rational a \c "n/d"

template <class INT>

inline void rational<INT>::set(INT n, INT d) {

    m_num = n;

    m_den = d;

    Simplify();

}

 

/** Copia desde \c "o".

    - El valor anterior de \c "*this" se pierde.

    \par Complejidad:

         O( \c 1 )

    \returns *this

    \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05

*/

template <class INT>

inline rational<INT>& rational<INT>::operator = (const rational<INT>& o) {

    m_num = o.m_num,

    m_den = o.m_den;

 

//  sobra invocar a "Simplify()" pues "o" ya está simplificado

    return *this;

}  // operator =

 

/** Intercambia los valores de \c "*this" y \c "o".

      \par Complejidad:

         O( \c 1 )

 

    \returns *this

 

    \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08

*/

template <class INT>

inline rational<INT>& rational<INT>::swap ( rational<INT>& o ) {

    #if 1

        rational tmp = o;

        o = *this;

        *this = tmp;

    #else

        // Esto NO funciona para objetos, métodos virtuales, etc.

        char tmp[ sizeof( *this ) ];

        memcpy( tmp,   o,     sizeof( *this ) ); // tmp = o;

        memcpy( o,    *this,  sizeof( *this ) ); // o = *this;

        memcpy( *this, tmp,   sizeof( *this ) ); // *this = tmp;

    #endif

    return *this;

}

 

/// Asignación desde un \c "long".

template <class INT>

inline rational<INT>& rational<INT>::operator = (INT entero) {

    m_num = entero;

    m_den = 1;

    return *this;

}  // operator =

 

/// Multiplica \c "*this" por \c "num".

template <class INT>

inline rational<INT>& rational<INT>::operator *= (const rational<INT>& num) {

    m_num *= num.m_num;

    m_den *= num.m_den;

    Simplify();

    return *this;

}  // operator *=

 

/**  Divide \c "*this" por el valor de \c "num".

    \pre

    - (num != 0)

*/

template <class INT>

inline rational<INT>& rational<INT>::operator /= (const rational<INT>& num) {

    m_num *= num.m_den;

    m_den *= num.m_num;

    Simplify();

    return *this;

}  // operator /=

 

/// \c "-x".

/// - Menos unario

/// - Calcula y retorna el valor \c "-x"

template <class INT>

inline rational<INT> rational<INT>::operator - () const {

    rational tmp = (*this);  // tmp.rational( *this );

    tmp.m_num = - tmp.m_num;

    return tmp;

}  // operator -

 

/// ¿ x == y ?

template <class INT>

inline bool operator == (const rational<INT> &x, const rational<INT> &y) {

    return (x.m_num == y.m_num) && (x.m_den == y.m_den);

/*  Nota:

    Como los números racionales siempre están simplificados, no puede

    ocurrir que [1/1] está almacenado como [3/3] y en consecuencia

    basta comparar los valores campo por campo para determinar si se

    da o no la igualdad.

*/

}  // operator ==

 

/// ¿ x < y ?

template <class INT>

inline bool operator < (const rational<INT> &x, const rational<INT> &y) {

    return (x.m_num * y.m_den) < (x.m_den * y.m_num);

/*  Nota:

    Una desigualdad de fracciones se preserva siempre que se

    multiplique a ambos lados por un número positivo. Por eso:

          [a/b] <       [c/d]   <==>

    [(b*d)*a/b] < [(b*d)*c/d]   <==>

          [d*a] < [b*c]

 

    [a/b] > [c/d] <==> [(b*d)*a/b] > [(b*d)*c/d] <==> [d*a] > [b*c]

 

    Debido a que el denominador siempre es un número positivo, el

    trabajo de comparar 2 racionales se puede lograr haciendo 2

    multiplicaciones de números enteros, en lugar de convertirlos

    a punto flotante para hacer la división, que es hasta un orden

    de magnitud más lento.

*/

//  return double(x.m_num) / double(x.m_den) < double(y.m_num) / double(y.m_den);

}  // operator <

 

/// ¿ x > y ?

template <class INT>

inline bool operator > (const rational<INT> &x, const rational<INT> &y) {

    return (y < x);

}  // operator >

 

/// ¿ x != y ?

template <class INT>

inline bool operator != (const rational<INT>& x, const rational<INT>& y) {

    return !(x == y);

}  // operator !=

 

/// ¿ x <= y ?

template <class INT>

inline bool operator <= (const rational<INT>& x, const rational<INT>& y) {

    return !(y < x);

}  // operator <=

 

/// ¿ x >= y ?

template <class INT>

inline bool operator >= (const rational<INT>& x, const rational<INT>& y) {

    return !(x < y);

}  // operator >=

 

/// Convertidor a punto flotante.

template <class INT>

inline double real(const rational<INT>& num) {

    return double (num.m_num) / double (num.m_den);

} // real()

 

/// Convertidor a punto fijo.

template <class INT>

inline INT integer(const rational<INT>& num) {

    return INT   (num.m_num /          num.m_den);

} // integer()

 

#if 0

    /// Convertidor a punto fijo

    inline rational::operator INT() {

        return INT (m_num / m_den);

    }  // rational::operator long

#endif

template <class INT>

bool check_ok_externo( const rational<INT>& r );

 

 

#include  <cstdlib>

#include  <cctype>     // isdigit()

 

 

/** Verifica la invariante de la clase \c rational.

    \par <em>Rep</em> Modelo de la clase:

    \code

    +---+

    | 3 | <==  m_num == numerador del número racional

    +---+

    |134| <==  m_den == denominador del número racional

    +---+

    \endcode

    - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep

 

    \remark

    Libera al programador de implementar el método \c Ok()

    - http://www.di-mare.com/adolfo/binder/c04.htm#sc11

*/

template <class INT>

bool check_ok( const rational<INT>& r ) {

    if (&r == 0) {

        /// - Invariante: ningún objeto puede estar almacenado en la posición nula.

        return false;

    }

 

    if ( ! (r.m_den > 0) )  {

        /// - Invariante: el denominador debe ser un número positivo.

        return false;

    }

    if (r.m_num == 0) {

        if ( r.m_den == 1 ) {

            /// - Invariante: el cero debe representarse con denominador igual a "1".

            return true;

        }

        else {

            return false;

        }

    }

    if ( ! ( mcd(r.m_num, r.m_den) == 1 ) ) {

        /// - Invariante: el numerador y el denominador deben ser primos relativos.

        return false;

    }

    return true;

} // check_ok()

 

/** Verifica la invariante de la clase \c rational.

    \remark

    Esta implementación nos se le mete al <em>Rep</em>

    (casi siempre no es posible implementar una función como ésta).

      - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep

    \remark

    Libera al programador de implementar el método \c Ok()

    - http://www.di-mare.com/adolfo/binder/c04.htm#sc11

*/

template <class INT>

bool check_ok_no_Rep( const rational<INT>& r ) {

    if (&r == 0) {

        /// - Invariante: ningún objeto puede estar almacenado en la posición nula.

        return false;

    }

 

    if ( ! (r.den() > 0) )  {

        /// - Invariante: el denominador debe ser un número positivo.

        return false;

    }

    if (r.num() == 0) {

        if ( r.den() == 1 ) {

            /// - Invariante: el cero debe representarse con denominador igual a "1".

            return true;

        }

        else {

            return false;

        }

    }

    if ( ! ( mcd(r.num(), r.den()) == 1 ) ) {

        /// - Invariante: el numerador y el denominador deben ser primos relativos.

        return false;

    }

    return true;

} // check_ok_no_Rep()

 

 

/** Calcula el Máximo Común Divisor de los números \c "x" y \c "y".

    - <code> mcd(x,y) >= 1 </code> siempre.

    - MCD <==> GCD: <em> Greatest Common Divisor </em>.

 

    \pre

    <code> (y != 0) </code>

 

    \remark

    Se usa el algoritmo de Euclides para hacer el cálculo.

 

    \par Ejemplo:

    \code

    2*3*5 == mcd( 2*2*2*2 * 3*3 * 5*5, 2*3*5 )

       30 == mcd( -3600, -30 )

    \endcode

*/

template <class INT>

INT mcd(INT x, INT y) {

    INT g = (x < 0 ? -x : x); // trabaja con valores positivos

    INT r = (y < 0 ? -y : y); // "r" es el resto

    INT temp;

 

    do {

        temp = r;

        r    = g % r;

        g    = temp;

    } while (0 != r);

 

    return g;

}  // mcd()

 

 

/** Simplifica el numerador y el denomidador.

    - Transforma el número rational de manera que el numerador y el

      denominador sean primos relativos, asegurando además que el

      denominador es siempre positivo.

    - Si <code>(m_num==0) ==> (m_den==1)</code>.

    - Simplifica la fracción para que \c m_num y \c m_den sean números

      primos relativos ie, <code>mcd(m_num,m_den) == 1</code>.

    - Asegura que \c m_den sea un número positivo.

    - Restaura la invariante de la clase \c rational.

*/

template <class INT>

void rational<INT>::Simplify() {

    if (m_num == 0) {

       m_den = 1;

    }

    INT divisor = mcd(m_num, m_den);

    if (divisor > 1) {   // ==> (divisor != 0)

        m_num /= divisor;

        m_den /= divisor;

    }

    if (m_den < 0) {

        m_num = -m_num;

        m_den = -m_den;

    }

}  // rational::Simplify()

 

/// Le suma a \c "*this" el valor de \c "otro".

template <class INT>

rational<INT>& rational<INT>::operator += (const rational<INT>& otro) {

    m_num  = m_num * otro.m_den + m_den * otro.m_num;

    m_den *= otro.m_den;

    Simplify();

 

    return *this;

}  // operator +=

 

 

/// Le resta a \c "*this" el valor de \c "otro".

template <class INT>

rational<INT>& rational<INT>::operator -= (const rational<INT>& otro) {

    INT oldm_den = m_den;

    INT oldm_num = m_num;

    INT d       = otro.m_den;

    INT n       = otro.m_num;

 

    m_den *= d;

    m_num = oldm_num * d - oldm_den * n;

    Simplify();

 

    return *this;

}  // operator -=

 

/// Establece el varlor de \c "*this" a partir de la hilera \c "nStr".

/// \pre \c "nStr" debe estar escrita en el formato "[num/den]".

template <class INT>

rational<INT>& rational<INT>::fromString (const char* nStr) {

    char ch;  // valor obtenido, caracter por caracter, de "nStr"

 

    bool es_positivo = true;    // manejo de los signos + y -

 

    // se brinca todo hasta el primer dígito

    do {

        ch = *nStr; nStr++;

        if (ch == '-') {  // cambia de signo

            es_positivo = !es_positivo;

        }

    } while (!isdigit(ch));

 

    // se traga el numerador

    INT num = 0;

    while (isdigit(ch)) { // convierte a decimal: izq --> der

        num = 10 * num + (ch-'0');

        ch = *nStr; nStr++;

    }

 

    // se brinca los blancos después del numerador

    while (isspace(ch)) {

        ch = *nStr; nStr++;

    }

 

    INT den;

    if (ch ==']') { // es un número entero

        den = 1;

    }

    else {

        do {  // se brinca todo hasta el denominador

            ch = *nStr; nStr++;

            if (ch == '-') {

                es_positivo = !es_positivo;

            }

        } while (!isdigit(ch));

 

        // se traga el denominador

        den = 0;

        while (isdigit(ch)) {

            den = 10 * den + (ch-'0');

            ch = *nStr; nStr++;

        }

        // Ya no importa si aparece o no el ']' del final del número

    }

 

 

    // le cambia el signo, si hace falta

    if (! es_positivo) {

        num = -num;

    }

    set( num, den );

    return *this;

}

 

/** Graba el valor de \c "r" en el flujo \c "COUT".

    - Graba el valor en el formato [num/den].

    - En particular, este es el operador que se invoca

      cuando se usa, por ejemplo, este tipo de instrucción:

     \code

          cout << r << q;

     \endcode

*/

template <class INT>

ostream& operator<< (ostream &COUT, const rational<INT>& r) {

    if ( r.m_den == 1 ) { // no hay parte fraccional

        return COUT << "[" << r.m_num << "]" ;

    } else {

        return COUT << "[" << r.m_num << "/" << r.m_den << "]" ;

    }

}  // operator <<

 

/** Lee del flujo de texto \c "CIN" el valor de \c "r".

    \pre

    El número rational debe haber sido escrito usando

    el formato "[r/den]", aunque es permisible usar

    algunos blancos.

    - Se termina de leer el valor sólo cuando encuentra \c "]".

    - <code> [ -+-+-+-+- 4 / -- -+ -- 32  ] </code> se lee como

      <code> [1/8] </code>

*/

template <class INT>

istream& operator >> (istream &CIN, rational<INT>& r) {

    char ch;  // valor leido, letra por letra, de "CIN"

 

    bool es_positivo = true;    // manejo de los signos + y -

 

    // se brinca todo hasta el primer dígito

    do {

        CIN >> ch;

        if (ch == '-') {  // cambia de signo

            es_positivo = !es_positivo;

        }

    } while (!isdigit(ch));

 

    // se traga el numerador

    r.m_num = 0;

    while (isdigit(ch)) { // convierte a decimal: izq --> der

        r.m_num = 10 * r.m_num + (ch-'0');

        CIN >> ch;

    }

 

    // se brinca los blancos después del numerador

    while (isspace(ch)) {

        CIN >> ch;

    }

 

    if (ch ==']') { // es un número entero

        r.m_den = 1;

    }

    else {

        do {  // se brinca todo hasta el denominador

            CIN >> ch;

            if (ch == '-') {

                es_positivo = !es_positivo;

            }

        } while (!isdigit(ch));

 

        // se traga el denominador

        r.m_den = 0;

        while (isdigit(ch)) {

            r.m_den = 10 * r.m_den + (ch-'0');

            CIN >> ch;

        }

 

        // El programa se duerme si en el flujo de entrada

        // NO aparece el caracter delimitador final "]",

        // pues la lectura termina hasta encontrar el "]".

        while (ch != ']') {

            CIN >> ch;

        }

    }   // corrección: Andrés Arias <[email protected]>

 

 

    // le cambia el signo, si hace falta

    if (! es_positivo) {

        r.m_num = -r.m_num;

    }

 

    r.Simplify();

    return CIN;

/*

    no detecta errores...

    [1/0] lo lee y no se queja

    [ !#!#!$#@! 3/ aaaa 4  jajaja ] lo lee como 3/4

    ... pero no se supone que el usuario cometa errores...

*/

 

}  // operator >>

 

/// \c "x+y".

/// - Calcula y retorna la suma \c "x+y".

template <class INT>

rational<INT> operator + (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

    res_den = x.m_den * y.m_den;

    res_num = x.m_num * y.m_den + x.m_den * y.m_num;

 

    return rational<INT>(res_num, res_den);

}  // operator + ()

 

/// \c "x-y".

/// - Calcula y retorna la resta \c "x-y".

template <class INT>

rational<INT> operator - (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

 

    res_den = x.m_den * y.m_den;

    res_num = x.m_num * y.m_den - x.m_den * y.m_num;

 

    return rational<INT>(res_num, res_den);

}  // operator - ()

 

/// \c "x*y".

/// - Calcula y retorna la multiplicación \c "x*y".

template <class INT>

rational<INT> operator * (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

 

    res_num = x.m_num * y.m_num;

    res_den = x.m_den * y.m_den;

 

    return rational<INT>(res_num, res_den);

}  // operator * ()

 

/// \c "x/y".

/// - Calcula y retorna la división \c "x/y".

/// \pre <code> y != 0 </code>

template <class INT>

rational<INT> operator / (const rational<INT> &x, const rational<INT> &y) {

    INT res_num, res_den;

    if (0 != y.m_num) {

        res_num = x.m_num * y.m_den;

        res_den = x.m_den * y.m_num;

    }

    return rational<INT>(res_num, res_den);

}  // operator / ()

 

#endif // rational_h

 

BigNum.cpp

 

#include "BigNum.h"

#include <Math.h>

#include <String.h>

#include <stdlib.h>

 

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

long BigNum::A_Numero()

{

      PNDoble Cte=0;

      int i,err=0;

      TMayor aux=0;

      for (i=0,err=Lis->MoverCte(Cte,'p');(err==0);i++,err=Lis->MoverCte(Cte,'s'))

            aux+=TMayor(Lis->ObtCte(Cte)*pow(double(MAXBASE),i)); /*Este casteo es para

            que no me ponga warnings por posible pérdida (double-->unsigned int) */

      return(signo*aux);

}

/*

BigNum::BigNum(unsigned short int a[],int cant)

{

      int i;

      signo=1;

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

            Lis->InsDespues(a[i]);

}

*/

BigNum::BigNum(int Nro)

{

      int num=Nro;

      Lis = new LDoble;

      if (num<0) {

            signo=-1;

            num=abs(num); }

      else

            signo=1;

      TDato n;

      PNDoble Cte=0;

//    Lis->MoverCte(Cte, 'p');

      if (num!=0)

            /*Lis->InsDespues(0);*/

            {

            do {

                  n=num % MAXBASE;

                  num=num / MAXBASE;

                  Lis->InsDespues(Cte,n); }

            while (num);

            }

}

BigNum::BigNum(unsigned short int a[],int cant,char sign) {

      int i;

      Lis = new LDoble;

      PNDoble Cte=0;

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

            Lis->InsDespues(Cte,a[i]);

      signo=sign;

}

BigNum::BigNum()

{

      Lis = new LDoble;

      signo=1;

}

 

BigNum::BigNum(char *s)

{

      char *p;

      int i;

      int neg=0;

      unsigned long int sum;

      Lis = new LDoble;

      p=s;

      if (*p=='-') {

            neg=1;

            p++;}

      signo=1;

      do {

            for(i=0,sum=0;((*p) && (i<9));i++,p++)

                  sum=sum*10+(*p-'0');

            (*this)*=pow(double(10),i);

            (*this)+=sum; }

      while (*p);

      if (neg)

            signo=-1;

}

ostream&  operator << (ostream&  s, const BigNum & m) {

     

      char cad[1000000];

      char cadaux[11];

      char* pcad;

      int lenaux;

      int neg=0;

      int i;

      BigNum aux(m);

      BigNum billon=1000000000,resto;

//    s<<endl<<"Hasta aqui todo bien[BigNum & billon=1000000000,resto;]"<<endl;

      cin.get();

 

      if (aux.signo==-1) {

            neg=1;

            aux.signo=1;

      }

      cad[999999]='\0';

      pcad=cad + 999998;

      *pcad = 0;

      s<<endl<<"Hasta aqui todo bien[while]"<<endl;

      cin.get();

      while (aux!=0) {

            resto=aux % billon;

            aux/=billon;

            _ltoa(resto.A_Numero(),cadaux,10);

            lenaux = strlen(cadaux);

            for (i=1; i<=lenaux; i++) {

                  pcad--;

                  *pcad = cadaux[lenaux-i];

                  }

            for (; i<=9; i++) {

                  pcad--;

                  *pcad = '0';

                  }

/*          strncpy(cero, ceros, 9-strlen(cadaux));

            strcpy(cad, strcat(cero, cad));

            strcpy(cad,strcat(cadaux,cad));*/

      }

//    s<<endl<<"Hasta aqui todo bien[fin de while]"<<endl;

      cin.get();

      pcad += 9-lenaux;

      if (!cad[0]) {

            cad[0]='\0';

            cad[1]='\0';

      }

//    s<<endl<<"Hasta aqui todo bien[cad]"<<endl;

      cin.get();

 

      if(neg) s <<'-'<< pcad;

      else s << pcad;

//    s<<endl<<"Hasta aqui todo bien[return]"<<endl;

      cin.get();

      return(s);

}

 

BigNum::BigNum(const BigNum& a)

{

//    copiar(a);

      Lis=a.Lis;

      Lis->CantRefs++;

      signo=a.signo;

}

 

BigNum::~BigNum()

{

//    Lis->Vaciar();

      if (Lis->CantRefs==1)

            delete Lis;

      else

            Lis->CantRefs--;

}

 

 

void BigNum::copiar(const BigNum& a)

{

      int err;

      PNDoble Cte=0, CteA=0;

 

      signo=a.signo;

      for (err=a.Lis->MoverCte(CteA, 'p');(!err);err=a.Lis->MoverCte(CteA, 's'))

            Lis->InsDespues(Cte,a.Lis->ObtCte(CteA));

}

/*    OPERADORES DE COMPARACIÓN     */

int BigNum::operator ==(const BigNum & a) const

{

      PNDoble Cte=0, CteA=0;

      int err=Lis->MoverCte(Cte,'p'),err_a=a.Lis->MoverCte(CteA,'p');

      TDato cif,cif_a;

      if ((Lis->CantElem()==a.Lis->CantElem()) && (signo==a.signo)) {

            while (!err)  {

                  cif=Lis->ObtCte(Cte);

                  cif_a=a.Lis->ObtCte(CteA);

                  if (cif!=cif_a)

                        return(0);

                  err=Lis->MoverCte(Cte,'s');

                  a.Lis->MoverCte(CteA,'s');}

            return(1);}

      else

            return(0);

}

 

int BigNum::operator !=(const BigNum & a) const

{

      return(!(*this==a));

}

 

int BigNum::operator >(const BigNum & a) const

{

      PNDoble Cte=0, CteA=0;

      if (signo!=a.signo)

            return((signo>a.signo));

      if (Lis->CantElem()==a.Lis->CantElem()) {

            int err=Lis->MoverCte(Cte,'u'),err_a=a.Lis->MoverCte(CteA,'u');

            TDato cif,cif_a;

            while (!err)  {

                  cif=Lis->ObtCte(Cte);

                  cif_a=a.Lis->ObtCte(CteA);

                  if (cif!=cif_a)

                        return((cif>cif_a));

                  err=Lis->MoverCte(Cte,'a');

                  a.Lis->MoverCte(CteA,'a');}

            return(0);}

      else

            return((Lis->CantElem()>a.Lis->CantElem()));

}

 

int BigNum::operator <(const BigNum & a) const

{

      PNDoble Cte=0, CteA=0;

      if (signo!=a.signo)

            return((signo<a.signo));

      if (Lis->CantElem()==a.Lis->CantElem()) {

            int err=Lis->MoverCte(Cte,'u'),err_a=a.Lis->MoverCte(CteA,'u');

            TDato cif,cif_a;

            while (!err)  {

                  cif=Lis->ObtCte(Cte);

                  cif_a=a.Lis->ObtCte(CteA);

                  if (cif!=cif_a)

                        return((cif<cif_a));

                  err=Lis->MoverCte(Cte,'a');

                  a.Lis->MoverCte(CteA,'a');}

            return(0);}

      else

            return((Lis->CantElem()<a.Lis->CantElem()));

}

 

int BigNum::operator >=(const BigNum & a) const

{

      return(!(*this<a));

}

 

int BigNum::operator <=(const BigNum & a) const

{

      return(!(*this>a));

}

 

BigNum& BigNum::operator = (const BigNum & a)

{

/*    if (&a==this)

            return(*this);

      else

      {     */

            /*BigNum aux;

            aux.copiar(a);*/

            Lis->Vaciar();

            copiar(a);

            return(*this);

     

}

 

 

BigNum operator + (const BigNum & a, const BigNum & b)

{

      BigNum r;

      PNDoble CteA, CteB, Cte=0;

 

      /*if (&a==&b)     {

            BigNum dos =2;

            r=a*dos;

            return(r);}     */

      if (a.signo!=b.signo) {

            if (a.signo==-1) {

                  const_cast<BigNum&>(a).signo=1;

                  r=b-a;

                  const_cast<BigNum&>(a).signo=-1;}

            else {

                  const_cast<BigNum&>(b).signo=1;

                  r=a-b;

                  const_cast<BigNum&>(b).signo=-1;}

            return(r);

            }

      else {

            int err_a=a.Lis->MoverCte(CteA,'p'),err_b=b.Lis->MoverCte(CteB,'p');

            TDato cif_a,cif_b;

            TDato pongo,mellevo=0;

            TMayor aux;

            while (!(err_a && err_b)) {

                  if (err_a)

                        cif_a=0;

                  else

                        cif_a=a.Lis->ObtCte(CteA);

                  if (err_b)

                        cif_b=0;

                  else

                        cif_b=b.Lis->ObtCte(CteB);

                  aux=cif_a+cif_b+mellevo;

                  pongo=aux % MAXBASE;

                  mellevo=aux / MAXBASE;

                  r.Lis->InsDespues(Cte,pongo);

                  err_a=a.Lis->MoverCte(CteA,'s');

                  err_b=b.Lis->MoverCte(CteB,'s');

            }

            if (mellevo)

                  r.Lis->InsDespues(Cte,mellevo);

            r.signo=a.signo;

            return(r);

      }

}

 

 

BigNum operator - (const BigNum & a, const BigNum & b)

{

      PNDoble CteA, CteB, Cte=0;

      BigNum r;

/*    if (&a==&b) {

            return(0);}     */

      if (a.signo!=b.signo) {

            if (b.signo==-1) {

                  const_cast<BigNum&>(b).signo=1;

                  r=a+b;

                  const_cast<BigNum&>(b).signo=-1;}

            else {

                  const_cast<BigNum&>(b).signo=-1;

                  r=a+b;

                  const_cast<BigNum&>(b).signo=1;}

            return(r);}

      else

            if (a.signo==-1){

                  const_cast<BigNum&>(a).signo=1;

                  const_cast<BigNum&>(b).signo=1;

                  r=b-a;

                  const_cast<BigNum&>(a).signo=-1;

                  const_cast<BigNum&>(b).signo=-1;

                  return(r);}

      //Si llega a este punto los dos son positivos

      if (a<b) {

            r=b-a;

            r.signo*=-1;

            return(r);}

      int err_a=a.Lis->MoverCte(CteA,'p'),err_b=b.Lis->MoverCte(CteB,'p');

      TDato cif_a,cif_b;

      TDato pongo,mellevo=0;

      int cont=0,i;

      signed long aux;

      while (!(err_a)) {

            cif_a=a.Lis->ObtCte(CteA);

            if (err_b)

                  cif_b=0;

            else

                  cif_b=b.Lis->ObtCte(CteB);

            aux=cif_a-cif_b-mellevo;

            if (aux<0) {

                  pongo=aux+MAXBASE;

                  mellevo=1;}

            else {

                  pongo=aux;

                  mellevo=0;}

            if (pongo==0)

                  cont++;

            else {

                  for(i=1;i<=cont;i++)

                        r.Lis->InsDespues(Cte,0);

                  cont=0;

                  r.Lis->InsDespues(Cte,pongo);}

            err_a=a.Lis->MoverCte(CteA,'s');

            err_b=b.Lis->MoverCte(CteB,'s');}

      return(r);

}

/*BigNum operator * (const class BigNum & a,const class BigNum & b) {

      BigNum & aaux;

      BigNum & baux;

      aaux=a;

      baux=b;

      return(aaux*baux);

}*/

 

 

BigNum operator * (const BigNum & a, const BigNum & b)

{

      BigNum r;

/*    if (&a==&b) {

            BigNum & baux=b;

            return(a*baux);}*/

      PNDoble CteA, CteB, Cte=0;

      r.signo=a.signo*b.signo;

      int err_b,err_a,err=1;

      int i,comienzo=0;

      TMayor aux;

      TDato mellevo=0,mellevo2=0;

      TMayor cif;

      for (err_b=b.Lis->MoverCte(CteB,'p');(!err_b);err_b=b.Lis->MoverCte(CteB,'s'),comienzo++) {

            for (i=0,err=r.Lis->MoverCte(Cte,'p');i<comienzo;i++)

                  err=r.Lis->MoverCte(Cte,'s');

            for (err_a=a.Lis->MoverCte(CteA,'p');(!err_a);err_a=a.Lis->MoverCte(CteA,'s')) {

                  aux = b.Lis->ObtCte(CteB) * a.Lis->ObtCte(CteA) + mellevo;

                  mellevo=aux / MAXBASE;

                  if (err) {

                        cif=aux % MAXBASE + mellevo2;

                        mellevo2=cif / MAXBASE;

                        r.Lis->InsDespues(Cte,cif % MAXBASE);}

                  else {

                        cif=r.Lis->ObtCte(Cte) + aux % MAXBASE + mellevo2;

                        mellevo2= cif / MAXBASE;

                        r.Lis->ModifCte(Cte,cif % MAXBASE);

                        err=r.Lis->MoverCte(Cte,'s');}

                   }

            if ((mellevo) || (mellevo2))

                  r.Lis->InsDespues(Cte,mellevo+mellevo2);

            mellevo=mellevo2=0;

      }

      return(r);

}

BigNum operator / (const BigNum & a, const BigNum & b)

{

      double signdivi=0, signresto;

      signed char signoa=a.signo,signob=b.signo;

      PNDoble CteA, CteB;

      PNDoble CteResto = 0, CteCociente = 0;

      TDato factor;

      BigNum cociente,resto;

      BigNum aux;

      int err,i,sale=0;

      int cantcif=0;

      const_cast<BigNum&>(a).signo=const_cast<BigNum&>(b).signo=resto.signo=cociente.signo=1; //Pongo todo positivo

      //Toma las dos cifras más significativas del divisor

      if (b.Lis->CantElem()<2)

            i=b.Lis->CantElem();

      else

            i=2;

      for(err=b.Lis->MoverCte(CteB,'u');(!err) && (i);i--,err=b.Lis->MoverCte(CteB,'a')) {

            cantcif++;

            signdivi+=pow(double(MAXBASE),i-1) * b.Lis->ObtCte(CteB);}

      if (cantcif==0)

            return(0);  //División por cero devuelve 0 (convención)

      for(err=a.Lis->MoverCte(CteA,'u');(!err);err=a.Lis->MoverCte(CteA,'a')) {

            resto.Lis->MoverCte(CteResto,'p');

            resto.Lis->InsAntes(CteResto,a.Lis->ObtCte(CteA));

            if (resto<b) {

                  if (cociente.Lis->CantElem())

                        cociente.Lis->InsAntes(CteCociente,0);}

            else {

                  if (resto.Lis->CantElem()>b.Lis->CantElem())

                        i=cantcif+1;

                  else

                        i=cantcif;

                  signresto=0;

                  for(err=resto.Lis->MoverCte(CteResto,'u');(!err) && (i);i--,err=resto.Lis->MoverCte(CteResto,'a'))

                        signresto+=pow(double(MAXBASE),i-1) * resto.Lis->ObtCte(CteResto);

                  factor=signresto/signdivi;

                  do {

                        aux=factor * b;

                        if (aux>resto)

                              factor--;

                        else

                              sale=1;}

                  while (!sale);

                  resto-=aux;

                  cociente.Lis->InsAntes(CteCociente,factor);

            } //Else

      } // for

      cociente.signo=signoa * signob;

      return(cociente);

}

 

BigNum operator % (const BigNum & a, const BigNum & b)

{

      double signdivi=0, signresto;

      signed char signoa=a.signo,signob=b.signo;

      PNDoble CteA, CteB;

      PNDoble CteResto = 0, CteCociente = 0;

      TDato factor;

      BigNum cociente,resto;

      BigNum aux;

      int err,i,sale=0;

      int cantcif=0;

      const_cast<BigNum&>(a).signo=const_cast<BigNum&>(b).signo=resto.signo=cociente.signo=1; //Pongo todo positivo

      //Toma las dos cifras más significativas del divisor

      if (b.Lis->CantElem()<2)

            i=b.Lis->CantElem();

      else

            i=2;

      for(err=b.Lis->MoverCte(CteB,'u');(!err) && (i);i--,err=b.Lis->MoverCte(CteB,'a')) {

            cantcif++;

            signdivi+=pow(double(MAXBASE),i-1) * b.Lis->ObtCte(CteB);}

      if (cantcif==0)

            return(0);  //División por cero devuelve 0 (convención)

      for(err=a.Lis->MoverCte(CteA,'u');(!err);err=a.Lis->MoverCte(CteA,'a')) {

            resto.Lis->MoverCte(CteResto,'p');

            resto.Lis->InsAntes(CteResto,a.Lis->ObtCte(CteA));

            if (resto<b) {

                  if (cociente.Lis->CantElem())

                        cociente.Lis->InsAntes(CteCociente, 0);}

            else {

                  if (resto.Lis->CantElem()>b.Lis->CantElem())

                        i=cantcif+1;

                  else

                        i=cantcif;

                  signresto=0;

                  for(err=resto.Lis->MoverCte(CteResto,'u');(!err) && (i);i--,err=resto.Lis->MoverCte(CteResto,'a'))

                        signresto+=pow(double(MAXBASE),i-1) * resto.Lis->ObtCte(CteResto);

                  factor=signresto/signdivi;

                  do {

                        aux=factor * b;

                        if (aux>resto)

                              factor--;

                        else

                              sale=1;}

                  while (!sale);

                  resto-=aux;

                  cociente.Lis->InsAntes(CteCociente,factor);

            } //Else

      } // for

      resto.signo=signoa;

      return(resto);

}

 

 

 

BigNum& BigNum::operator++()

{

//    BigNum r=*this;

      PNDoble Cte;

 

      if (signo==-1) {

            BigNum a;

            signo=1;

            (*this)--;

            if (!Lis->Vacia()) //Cero se considera positivo

                  signo=-1;}

      else {

            TDato cif,mellevo=1;

            int err=Lis->MoverCte(Cte,'p');

            while ((!err) && (mellevo)) {

                  cif=Lis->ObtCte(Cte);

                  if (cif==(MAXBASE-1)) {

                        Lis->ModifCte(Cte,0);

                        Lis->MoverCte(Cte,'s');}

                  else {

                        Lis->ModifCte(Cte,cif+1);

                        mellevo=0;}

            }

            if (mellevo)

                  Lis->InsDespues(Cte,1);}

      return(*this);

}

 

BigNum& BigNum::operator--()

{

//    BigNum r=*this;

      PNDoble Cte;

      if (signo==-1) {

            BigNum a;

            signo=1;

            (*this)++;

            signo=-1;}

      else

      {

            TDato cif,mellevo=1;

            int err=Lis->MoverCte(Cte,'p');

            while ((!err) && (mellevo)) {

                  cif=Lis->ObtCte(Cte);

                  if (!cif) {

                        Lis->ModifCte(Cte,MAXBASE-1);

                        Lis->MoverCte(Cte,'s');}

                  else {

                        Lis->ModifCte(Cte,cif-1);

                        mellevo=0;}

            }

            if (Lis->Vacia())  //Era cero queda -1, signo negativo

                  signo=-1;

            if (mellevo)

                  Lis->InsDespues(Cte,1);

            if ((Lis->CantElem()==1) && (Lis->ObtCte(Cte)==0))

                  Lis->Vaciar();

            else {

                  Lis->MoverCte(Cte,'u');

                  if (Lis->ObtCte(Cte)==0)

                        Lis->ElimCte(Cte);

            }

      }

      return(*this);

}

 

BigNum& BigNum::operator +=(const BigNum & a)

{

/*    if (&a==this)

            return((*this)*=2);*/

      if (a.signo!=signo) {

            if (a.signo==-1) {

                  const_cast<BigNum&>(a).signo=1;

                  (*this)-=a;

                  const_cast<BigNum&>(a).signo=-1;}

            else {

                  signo=1;

                  (*this)-=a;

                  signo*=-1;}

            return(*this);}

      TDato mellevo=0;

      TMayor aux;

      PNDoble Cte, CteA;

      int err=Lis->MoverCte(Cte,'p'),err_a=a.Lis->MoverCte(CteA,'p');

      while ((!err) && (!err_a)) {

            aux=Lis->ObtCte(Cte)+a.Lis->ObtCte(CteA)+mellevo;

            Lis->ModifCte(Cte,aux % MAXBASE);

            mellevo=aux / MAXBASE;

            err=Lis->MoverCte(Cte,'s');

            err_a=a.Lis->MoverCte(CteA,'s');}

      if (!err_a)

            if (mellevo)

                  if (!err) {

                        Lis->MoverCte(Cte,'u');

                        Lis->InsDespues(Cte,mellevo);}

                  else {

                        do {

                              aux=Lis->ObtCte(Cte)+mellevo;

                              Lis->ModifCte(Cte,aux % MAXBASE);

                              mellevo=aux / MAXBASE;

                              err=Lis->MoverCte(Cte,'s');}

                        while ((!err) && (mellevo));}

      else

            if (mellevo) {

                  do {

                        aux=a.Lis->ObtCte(CteA)+mellevo;

                        Lis->InsDespues(Cte,aux % MAXBASE);

                        mellevo=aux / MAXBASE;

                        err_a=a.Lis->MoverCte(CteA,'s');}

                  while ((!err_a) && (mellevo));}

            while (!err_a) {

                  Lis->InsDespues(Cte,a.Lis->ObtCte(CteA));

                  err_a=a.Lis->MoverCte(CteA,'s');}

      if (mellevo)

            Lis->InsDespues(Cte,mellevo);

      return(*this);

}

BigNum& BigNum::operator-=(const BigNum & a)

{

      if (&a==this) { // si se resta a sí mismo da cero

            Lis->Vaciar();

            signo=1;

            return(*this);}

      if (a.signo==-1) {

            const_cast<BigNum&>(a).signo=1;

            (*this)+=a;

            const_cast<BigNum&>(a).signo=-1;

            return(*this);}

      else

            if (signo==-1) {

                  signo=1;

                  (*this)+=a;

                  signo=-1;

                  return(*this);}

      PNDoble Cte, CteA;

      if (a>(*this))

            (*this)=(*this)-a;  //Si a es mayor debo hacer resta común

      else {

            TDato mellevo=0;

            signed long int aux;

            int err=Lis->MoverCte(Cte,'p'),err_a=a.Lis->MoverCte(CteA,'p');

            while (!err_a) {

                  aux=Lis->ObtCte(Cte)-a.Lis->ObtCte(CteA)-mellevo;

                  if (aux<0) {

                        Lis->ModifCte(Cte,aux+MAXBASE);

                        mellevo=1;}

                  else {

                        Lis->ModifCte(Cte,aux);

                        mellevo=0;}

                  Lis->MoverCte(Cte,'s');

                  err_a=a.Lis->MoverCte(CteA,'s');}

            while (mellevo) {

                  aux=Lis->ObtCte(Cte)-mellevo;

                  if (aux<0) {

                        Lis->ModifCte(Cte,aux+MAXBASE);

                        mellevo=1;}

                  else {

                        Lis->ModifCte(Cte,aux);

                        mellevo=0;}

                  Lis->MoverCte(Cte,'s');}

            for (err=Lis->MoverCte(Cte,'u');((!err) && (Lis->ObtCte(Cte)==0));err=Lis->MoverCte(Cte,'u'))

                  Lis->ElimCte(Cte); // Elimina los ceros que hubieran quedado a izquierda

      }

      return(*this);                     

}

 

BigNum& BigNum::operator *=(const BigNum & a)

{

      *this=a*(*this);

      return(*this);

}

 

BigNum& BigNum::operator /=(const BigNum & a)

{

      *this=(*this)/a;

      return(*this);

}

 

BigNum& BigNum::operator %=(const BigNum & a)

{

      *this=(*this)%a;

      return(*this);

}

 

LDoble.cpp

 

#include "LDoble.h"

 

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

 

LDoble::LDoble():Prim(0),Ult(0),CantNodos(0), CantRefs(1)

{

 

}

 

LDoble::~LDoble()

{

      CantRefs--;

      if (CantRefs==0)

            Vaciar();

}

Boolean LDoble::Vacia()

{    

      if (Prim==0)

            return(TRUE);

      else

            return(FALSE);

}

int LDoble::MoverCte(PNDoble& Cte, char direccion)

{

      if (Vacia()==FALSE) {

            switch (direccion) {

                  case 'p':Cte=Prim;

                               break;

                  case 'u':Cte=Ult;

                               break;

                  case 'a':if (Cte->Ant==0)

                                    return(1);

                               else

                                    Cte=Cte->Ant;

                               break;

                  case 's':if (Cte->Sig==0)

                                    return(1);

                               else

                                    Cte=Cte->Sig;

                               break;

                  default : return(1);

                               break;

            }

            return(0);

      }

      else

      {     Cte = 0;

            return(1);}

}

     

 

int LDoble::InsAntes(PNDoble& Cte, TDato dat){

      NDoble *p=new NDoble;

      p->Dato=dat;

      p->Sig=Cte;

      if (Cte!=0)

            if (Cte->Ant==0) {

                  p->Ant=0;

                  Cte->Ant=p;

                  Prim=p;}

            else {

                  p->Ant=Cte->Ant;

                  Cte->Ant->Sig=p;

                  Cte->Ant=p;}

      else{

            Prim=p;

            Ult=p;

            p->Ant=0;

            p->Sig=0;

      }

      Cte=p;

      CantNodos++;

      return(0);

}

 

int LDoble::InsDespues(PNDoble& Cte, TDato dat){

      NDoble *p=new NDoble;

      p->Dato=dat;

      p->Ant=Cte;

      if (Cte!=0)

            if (Cte->Sig==0) {

                  p->Sig=0;

                  Cte->Sig=p;

                  Ult=p;}

            else {

                  p->Sig=Cte->Sig;

                  Cte->Sig->Ant=p;

                  Cte->Sig=p;}

      else{

            Prim=p;

            Ult=p;

            p->Ant=0;

            p->Sig=0;

      }

      Cte=p;

      CantNodos++;

      return(0);

}

TDato LDoble::ObtCte(PNDoble Cte){

      return(Cte->Dato);}

 

int LDoble::ModifCte(PNDoble& Cte, TDato dat){

      if (Cte!=0) {

            Cte->Dato=dat;

            return(0);}

      else

            return(1);

}

int LDoble::ElimCte(PNDoble& Cte){

      if (Cte==0)

            return(1);

      else{

            if (Cte->Sig==0)

                  Ult=Cte->Ant;

            else

                  Cte->Sig->Ant=Cte->Ant;

            if (Cte->Ant==0)

                  Prim=Cte->Sig;

            else

                  Cte->Ant->Sig=Cte->Sig;

            NDoble *p=Cte;

            if (Cte->Sig)

                  Cte=Cte->Sig;

            else

                  Cte=Cte->Ant;

            delete p;

            CantNodos--;

            return(0);

      }

}

 

void LDoble::Vaciar() {

      NDoble *p;

      PNDoble Cte;

      Cte=Prim;

      while (Cte) {

            p=Cte;

            Cte=p->Sig;

            delete p;

      }

      Prim=0;

      Ult=0;

      CantNodos=0;

}

 

int LDoble::CantElem() {

      return(CantNodos);

}

 

test_rational.cpp

 

#include "ADH_test.h"

#include "rational.h"

#include "decimal.h"

 

 

/// Ambiente de prueba para la clase complicada para probar \c rational.

/// - No es necesario definir el método \c tearDown() pues para este

///   caso específico \c TestFixture::tearDown() funciona bien.

template <class INT>

class rational_TestFixture : public TestCase {

protected:

    rational<INT> m_half, m_quarter, m_one, m_eight, m_five;

public:

    virtual void setUp(); ///< Establece el ambiente de prueba

}; // rational_TestFixture

template <class INT>

void rational_TestFixture<INT>::setUp() {

    m_half.set(1,2);

    m_quarter.set(1,4);

    m_one.set(1);

      m_eight.set(1,8);

      m_five.set(1,5);

}

 

template <class INT>

class rational_Test_Add : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Add<INT>::run() {

    assertTrue( m_half+m_quarter == rational<INT>(30,40) );

    assertTrue( rational<INT>(30,40) == m_quarter+m_half );

 

    assertTrue( m_one+m_quarter == rational<INT>(125,100) );

    assertTrue( rational<INT>(125,100) == m_quarter+m_one );

 

    assertTrue(  rational<INT>(1,3) != rational<INT>(33,100)  );

 

      assertTrue( m_eight+m_five == rational<INT>(13,40) );

      assertTrue( rational<INT>(13,40) == m_five+m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

    m_half = m_quarter = m_one = m_eight = m_five = 0;

    return nError() == 0;

}

 

/// Clase para probar la resta de racionales.

template <class INT>

class rational_Test_Substract : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Substract<INT>::run() {

    assertTrue(  m_half-m_quarter == rational<INT>(10,40) );

    assertTrue(  rational<INT>(-10,40)  == m_quarter-m_half );

 

    assertTrue(  m_one-m_quarter   == rational<INT>(75,100) );

    assertTrue(  rational<INT>(-75,100) == m_quarter-m_one  );

 

    assertEquals( rational<INT>(-3,4) ,  m_quarter-m_one );

    assertTrue(   rational<INT>(75,100) == m_one-m_quarter );

 

      assertTrue( m_eight-m_five == rational<INT>(-3,40) );

      assertTrue( rational<INT>(3,40) == m_five-m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

    m_half = m_quarter = m_one = m_eight = m_five = 0;

    return nError() == 0;

}

 

template <class INT>

class rational_Test_Multiplication : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Multiplication<INT>::run() {

    assertTrue( m_half * m_quarter == rational<INT>(10,80) );

    assertTrue( rational<INT>(10,80) == m_quarter * m_half );

 

    assertTrue( m_one * m_quarter == rational<INT>(10,40) );

    assertTrue( rational<INT>(10,40) == m_quarter * m_one );

 

    assertTrue(  rational<INT>(1,3) != rational<INT>(33,100)  );

 

      assertTrue( m_eight*m_five == rational<INT>(1,40) );

      assertTrue( rational<INT>(1,40) == m_five*m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

 

      { // 2^1024 * 3 ^ 512;

      INT deDOS=1, deTRES=1;

      for (int i=0; i<1024; ++i ) {

      INT elOTRO = (2 * deDOS);

      assertTrue( deDOS < elOTRO );

      deDOS = elOTRO;

      }

      for (int i=0; i<512; ++i ) {

      deTRES *= 3;

      }

      assertTrue( mcd<INT>(deDOS, deTRES) == 1 );

      }

 

    m_half = m_quarter = m_one = m_eight = m_five = 0;

 

    return nError() == 0;

}

 

 

template <class INT>

class rational_Test_Division : public rational_TestFixture<INT> {

public:

    bool run();

}; // rational_TestFixture

 

/// Función principal del la prueba

/// - Requiere que recién haya sido ejecutado \c setUp()

template <class INT>

bool rational_Test_Division<INT>::run() {

    assertTrue( m_half/m_quarter == rational<INT>(4,2) );

    assertTrue( ( rational<INT>(1,2) ) == (m_quarter/m_half) );

 

    assertTrue( m_one/m_quarter == rational<INT>(4) );

    assertTrue( rational<INT>(1,4) == m_quarter/m_one );

 

    assertTrue(  rational<INT>(1,3) != rational<INT>(33,100)  );

 

      assertTrue( m_eight/m_five == rational<INT>(5,8) );

      assertTrue( rational<INT>(8,5) == m_five/m_eight );

 

    // Esto está aquí sólo para destrozar los valores de *this

    m_half = m_quarter = m_one = m_eight = m_five = 0;

    return nError() == 0;

}

 

/// Programa principal desde donse se invocan todas las pruebas

 

int main() {

      rational_Test_Add< decimal >        rational_Test_Add_Instance;

 

    cout << endl << endl << "1) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Add_Instance.setUp();

    rational_Test_Add_Instance.run();

    Report(cout, rational_Test_Add_Instance);

    if (rational_Test_Add_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Add_Instance.toString();

    }

   

    rational_Test_Substract< decimal >  rational_Test_Substract_Instance;

    cout << endl << endl << "2) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Substract_Instance.setUp();

    rational_Test_Substract_Instance.run();

    Report(cout, rational_Test_Substract_Instance);

    if (rational_Test_Substract_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Substract_Instance.toString();

    }

 

      rational_Test_Multiplication< decimal >        rational_Test_Multiplication_Instance;

 

    cout << endl << endl << "1) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Multiplication_Instance.setUp();

    rational_Test_Multiplication_Instance.run();

    Report(cout, rational_Test_Multiplication_Instance);

    if (rational_Test_Multiplication_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Multiplication_Instance.toString();

    }

 

      rational_Test_Division< decimal >        rational_Test_Division_Instance;

 

    cout << endl << endl << "1) Prueba directa con \"TestFixture\"" << endl;

    rational_Test_Division_Instance.setUp();

    rational_Test_Division_Instance.run();

    Report(cout, rational_Test_Division_Instance);

    if (rational_Test_Division_Instance.nError() != 0 ) {

        cout << "El error" << endl << rational_Test_Division_Instance.toString();

    }

 

      cin.get();

 

      return 0;

}

 

 

 

Bibliografía:               

 

http://di-mare.com/pub/pg2/

http://www.di-mare.com/adolfo/cursos/2007-2/p2-ta-4.htm

 

 

 

Hosted by www.Geocities.ws

1