Universidad de Costa Rica

 

 

 

Ciencias de la Computación e Informática

 

 

 

Curso:

Programación II

 

 

 

Documentación

II tarea Programada

 

 

 

Profesor: Adolfo Di-Mare

 

 

 

Alumnos:

Elsie Castro Villalobos A41369

Armando Soto Rodríguez A55609

 

 

 

 

30/08/2007

 

Índice

 

 

Introducción: 3

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

Descripción del problema a resolver: 3

Abstracción: 4

Especificación de la clase: 4

Operaciones / métodos: 4

Especificación del programa: 5

Implementación. 6

Invariante de la clase: 6

Compilador usado. 6

¿Cómo compilar el programa?. 6

Guía de uso del programa. 6

Datos de prueba del programa. 7

Formato de los datos de prueba. 7

Entradas vs Salidas esperadas: 7

Código fuente. 9

rational.h. 9

adh_port.h. 21

rat-calc.cpp. 25

Bibliografía. 26

 

 

 

 

 

Introducción:

 

         

          El siguiente trabajo a realizar se basa en la utilización de plantillas para la fabricación de clases, con lo cual se puede emplear el programa utilizando diferente tipos de clases, como por ejemplo los tipos básicos: short, int, long, long long.

 

          La idea de emplantillar clases es sumamente importante para la reutilización de módulos disponibles, lo cual disminuye el tiempo de fabricación de programas.

    

 

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

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

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

 

 

Descripción del problema a resolver:

 

Usar una clase ya implementada para obtener un clase equivalente, pero emplantillada. La idea es construir nuevas piezas de programación con base en las ya existentes para aprovechar los módulos disponibles.

Tomar la implementación de la clase rational que le fue entregada en clase y mejórela para que sea posible crear números racionales a partir de enteros cortos o largos, o a partir de otras clases aritmética.

 

 

 

 

 

 

 

Abstracción:

  Especificación de la clase:

 

       La clase racional sirve para definir un número racional y así poder realizar operaciones matemáticas básicas con los mismos; suma, resta multiplicación y división, además esta clase esta emplantillada lo cual permite definir un racional a base de diferentes tipos de clases como por ejemplo: short, int, long.

 

 

Operaciones / métodos:

 

void Simplify(): Simplifica la fracción para que \c m_num y \c m_den sean números primos relativos.

 

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.

 

 

  Especificación del programa:

 

            El programa realiza operaciones básicas, suma, resta, multiplicación, división y comparaciones ( = =, <,  >, < =, > =, !=) con los números racionales, ademas de mostrar el resultado en su forma canonica.

 

 

 

Implementación

 

Invariante de la clase:

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

       -El denominador debe ser un número positivo.

       -El cero debe representarse con denominador igual a "1".

       -El numerador y el denominador deben ser primos relativos.

 

Compilador usado

       Visual Studio 2005

 

¿Cómo compilar el programa?

       Abrir el proyecto y darle click en la opción build, build rat-calc.

 

Guía de uso del programa

       Al iniciar el programa los números racionales se ingresan de  la siguiente manera: [ 5/6 ] .

       Se utilizaran los operadores matemáticos básicos para la realización de los diferentes cálculos requeridos.

Por ejemplo:

  [0] > + [ 2 / 3 ]
    [2/3] > / [ 6 / 2 ]
    [2/9] > * [ 18 ]
    [4] > - [ 45 / 9 ]
    [-1] > / [ 13 / 8 ]
    [-8/13] > * [ 2 ]
    [-16/13] > + [ 7 ]
    [75/13] > .
    [75/13] >

 

       Para terminar el programa solamente ingrese un punto cuando lo crea conveniente.

Datos de prueba del programa

 

  Formato de los datos de prueba

            Los datos deberán ser ingresados de la siguiente manera:

  [0] > + [ 2 / 3 ]
    [2/9] > * [ 18 ]
    [-1] > / [ 13 / 8 ]
    [75/13] > .
    
 
 

 

   Entradas vs Salidas esperadas:

 

 

          Utilizando la clase con el tipo long:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Utilizando la clase con el tipo int:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Utilizando la clase con el tipo short:

 

 

 

 

 

 

 

 

 

 

 

 

 


Código fuente

rational.h

 

#ifndef rational_h

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

 

#include "ADH_port.h"

 

#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()

//  excluidos porque producen ambigüedad con operadores aritméticos

//  operator double () { return double(m_num) / double(m_den); }

//  operator long   () { return        m_num  /        m_den ; }

}; // 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

 

// EOF: rational.h

 

adh_port.h

 

#ifndef ADH_port_h

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

 

// Documentados acá para Doxygen

#undef  CLOSE_namespace

#undef  USING_namespace

#undef  OPEN_namespace

 

/// Abre namespace   \c "N"

#define OPEN_namespace(N) namespace N {

 

/// Cierra namespace \c "N"

#define CLOSE_namespace(N) }

 

/// Usa namespace    \c "N"

#define USING_namespace(N) using namespace N

 

// Los anula para luego definirlos dentro del #ifdef correcto

#undef  CLOSE_namespace

#undef  USING_namespace

#undef  OPEN_namespace

 

#ifdef DOXYGEN_COMMENT   // Documentados acá para Doxygen

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

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

    /// ADH son las siglas de \c [email protected]

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

    #define INCLUDE_fstream   Truco para "include <fstream>"   portable

    #define INCLUDE_io        Truco para "include <io>"        portable

    #define INCLUDE_iomanip   Truco para "include <iomanip>"   portable

    #define INCLUDE_iostream  Truco para "include <iostream>"  portable

    #define INCLUDE_list      Truco para "include <list>"      portable

    #define INCLUDE_map       Truco para "include <map>"       portable

    #define INCLUDE_stdexcept Truco para "include <stdexcept>" portable

    #define INCLUDE_vector    Truco para "include <vector>"    portable

#endif

 

// Borland C++

#ifdef __BORLANDC__               ///< Definida para Borland C++

    #if (__BORLANDC__ <= 0x0410)  //   Identifica a BC++ v3.1 y anterior

 

        // Declara el tipo "bool" porque BC++ v3.1 NO tiene "bool"

        #ifndef _bool_h

        #define _bool_h

            #undef false

            #undef true

            #undef bool

 

            typedef int bool;

            const int false = 0;

            const int true  = ! false; // BC++ v3.1 NO tiene "bool"

        #endif

 

        class istream; class ostream;

 

        #define using              // BC++ v3.1 NO tiene "namespace"

        #define namespace

        #define std

        #define ADH

 

        #define OPEN_namespace(N)  // BC++ v3.1 NO tiene "namespace"

        #define CLOSE_namespace(N)

        #define USING_namespace(N)

 

        #ifdef INCLUDE_fstream

            #include  <fstream.h>

        #endif

        #ifdef INCLUDE_io

            #include  <io.h>

        #endif

        #ifdef INCLUDE_iomanip

            #include  <iomanip.h>

        #endif

        #ifdef INCLUDE_iostream

            #include  <iostream.h>

        #endif

        #ifdef INCLUDE_list

            #include  <list.h>

        #endif

        #ifdef INCLUDE_map

            #include  <map.h>

        #endif

        #ifdef INCLUDE_set

            #include  <set.h>

        #endif

        #ifdef INCLUDE_stdexcept

            #include  <stdexcept.h>

        #endif

        #ifdef INCLUDE_string

            #include  <string.h>

        #endif

        #ifdef INCLUDE_vector

            #include  <vector.h>

        #endif

    #endif

 

    #if (__BORLANDC__ >  0x0410)  // Versiones posteriores a BC++ v3.1

        #define OPEN_namespace(N) namespace N {

        #define CLOSE_namespace(N) }

        #define USING_namespace(N) using namespace N

        #error Ajuste ADH_port.h para compìlar con versiones nuevas de BC++

    #endif

#endif

 

// Microsoft C++ (Visual Studio)

#ifdef _MSC_VER                   ///< Definida para Micrsoft C++

    // namespace

    #define OPEN_namespace(N) namespace N {

    #define CLOSE_namespace(N) }

    #define USING_namespace(N) using namespace N

 

    #if (_MSC_VER >= 1300)        //   Identifica a VC++ .net

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

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

        using namespace std;

 

        #ifdef INCLUDE_fstream

            #include  <fstream>

        #endif

        #ifdef INCLUDE_io

            #include  <io>

        #endif

        #ifdef INCLUDE_iomanip

            #include  <iomanip>

        #endif

        #ifdef INCLUDE_iostream

            #include  <iostream>

        #endif

        #ifdef INCLUDE_list

            #include  <list>

        #endif

        #ifdef INCLUDE_map

            #include  <map>

        #endif

        #ifdef INCLUDE_set

            #include  <set>

        #endif

        #ifdef INCLUDE_stdexcept

            #include  <stdexcept>

        #endif

        #ifdef INCLUDE_string

            #include  <string>

        #endif

        #ifdef INCLUDE_vector

            #include  <vector>

        #endif

    #endif

 

    #if (_MSC_VER < 1300)         //   Identifica a VC++ v6 y anterior

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

        using namespace std;

        // Antes de MSC++ .NET hay que usar <.h>

        #ifdef INCLUDE_fstream

            #include  <fstream.h>

        #endif

        #ifdef INCLUDE_io

            #include  <io.h>

        #endif

        #ifdef INCLUDE_iomanip

            #include  <iomanip.h>

        #endif

        #ifdef INCLUDE_iostream

            #include  <iostream.h>

        #endif

        #ifdef INCLUDE_list

            #include  <list.h>

        #endif

        #ifdef INCLUDE_map

            #include  <map.h>

        #endif

        #ifdef INCLUDE_set

            #include  <set.h>

        #endif

        #ifdef INCLUDE_stdexcept

            #include  <stdexcept.h>

        #endif

        #ifdef INCLUDE_string

            #include  <string.h>

        #endif

        #ifdef INCLUDE_vector

            #include  <vector.h>

        #endif

    #endif

#endif

 

#endif // ADH_port_h

 

// EOF: ADH_port.h

 

rat-calc.cpp

 

#include "rational.h"

#include <limits.h>

 

/// Función principal en la que empieza la ejecución del programa

//template <class INT>

int main() {

 

    rational<int> r,        // último valor ingresado

                  acum;     // acumulador de la calculadora

    char     op;       // operación a efectuar

 

    // inicializa el acumudador

    acum = 0;

 

    // despliega el valor inicial del acumulador

    cout << acum << " > ";

    cin  >> op;

 

 

    // ciclo para leer la siguiente operación a efectuar

    while (op != '.') {

        // valor a operar con el acumulador

        cin >> r;             // operator>> (cin, r);

 

        // selección de la operación a realizar

        switch (op) {

            case '+': acum += r;          break; // acum.op += ( r );

            case '-': acum  = acum - r;   break; // acum.op  = (op- (acum, r));

            case '*': acum *= r;          break; // acum.op *= ( r );

            case '/': acum  = acum / r;   break; // acum.op  = (op/ (acum, r));

        default:

            // operación inválida

            cout << "\n(" << op << ")==> Operación inválida\n";

        }

 

        // despliega el nuevo valor del acumulador

        cout << acum << " > ";

        cin.ignore(INT_MAX, '\n');

        cin >> op;

    }

 

    // despliega el valor final del acumulador

    cout << acum << " > ";

    return 0;

}  // main()

 

 

      

Bibliografía:               

 

http://di-mare.com/pub/pg2/

http://di-mare.com/pub/pg2/00-Material-CI-1201.htm

http://www.di-mare.com/adolfo/cursos/2007-2/p2-ta-2.htm

 

 

 

Hosted by www.Geocities.ws

1