// rational.h (c) 2005 adolfo@di-mare.com /** \file rational.h \brief Declara el tipo \c "rational". - La clase \c rational implementa las operaciones aritméticas principales para números rationales. - [1/3] == [2/6] == ... [9/27] == ... - [1/3] * [2/6] / [3/9] - [9/27] - Permite usar racionales en cualquier sitio en donde se puedan usar valores numéricos. \author Adolfo Di Mare \date 2005 */ #ifndef rational_h #define rational_h ///< Evita la inclusión múltiple #define INCLUDE_iostream // ADH_port.h ==> #include #include "ADH_port.h" OPEN_namespace(ADH) // ADH_port.h ==> namespace ADH { USING_namespace(ADH); // ADH_port.h ==> using namespace ADH; /** La clase \c rational implementa las operaciones aritméticas principales para números rationales. - [1/3] == [2/6] == ... [9/27] == ... - [1/3] * [2/6] / [3/9] - [9/27] */ class rational { private: long m_num; ///< Numerador long m_den; ///< Denominador void Simplify(); public: // constructores rational() : m_num(0), m_den(1) { } ///< Constructor de vector rational(long num) : m_num(num), m_den(1) { } ///< Constructor a partir de un valor entero rational(long num, long den) : m_num(num), m_den(den) { Simplify(); } ///< Constructor a partir de un valor quedbrado /// Constructor de copia rational(const rational& o) { m_num = o.m_num; m_den = o.m_den; } ~rational() { } ///< Destructor void set(long num=0, long den=1); // Le cambia el valor a \c "*this" long num() const { return m_num; } ///< Copia del numerador long 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 = (long); rational& swap ( rational& ); rational& operator += (const rational&); rational& operator -= (const rational&); // rational& operator *= (const rational&); rational& operator /= (const rational&); rational operator - () const; // menos unario friend rational operator + (const rational&, const rational&); friend rational operator - (const rational&, const rational&); friend rational operator * (const rational&, const rational&); friend rational operator / (const rational&, const rational&); friend bool operator == (const rational&, const rational&); friend bool operator < (const rational&, const rational&); friend bool operator != (const rational&, const rational&); friend bool operator <= (const rational&, const rational&); friend bool operator >= (const rational&, const rational&); friend bool operator > (const rational&, const rational&); friend std::ostream& operator << (std::ostream &, const rational& ); friend std::istream& operator >> (std::istream &, rational& ); rational& fromString (const char* nStr); friend double real (const rational& ); // Conversión a real friend long integer(const rational& ); // Conversión a long friend bool check_ok( const rational& 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 long mcd(long x, long y); // Calcula el Máximo Común Divisor /// Sinónimo de \c mcd(x,y) [ inline ] inline long gcd(long x, long y) { return mcd(x,y); } /// Cambia el valor del número rational a \c "n/d" inline void rational::set(long n, long 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 */ inline rational& rational::operator = (const rational& 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 */ inline rational& rational::swap ( rational& o ) { #if 1 rational tmp = o; o = *this; // o.operator=( *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 rational& rational::operator = (long entero) { m_num = entero; m_den = 1; return *this; } // operator = #if 0 /// Multiplica \c "*this" por \c "num". inline rational& rational::operator *= (const rational& num) { m_num *= num.m_num; m_den *= num.m_den; Simplify(); return *this; } // operator *= #endif rational & operator *= ( rational & a, const rational & b ); /** Divide \c "*this" por el valor de \c "num". \pre - (num != 0) */ inline rational& rational::operator /= (const rational& 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" inline rational rational::operator - () const { rational tmp = (*this); // tmp.rational( *this ); tmp.m_num = - tmp.m_num; return tmp; } // operator - /// ¿ x == y ? inline bool operator == (const rational &x, const rational &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 ? inline bool operator < (const rational &x, const rational &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 ? inline bool operator > (const rational &x, const rational &y) { return (y < x); } // operator > /// ¿ x != y ? inline bool operator != (const rational& x, const rational& y) { return !(x == y); } // operator != /// ¿ x <= y ? inline bool operator <= (const rational& x, const rational& y) { return !(y < x); } // operator <= /// ¿ x >= y ? inline bool operator >= (const rational& x, const rational& y) { return !(x < y); } // operator >= /// Convertidor a punto flotante. inline double real(const rational& num) { return double (num.m_num) / double (num.m_den); } // real() /// Convertidor a punto fijo. inline long integer(const rational& num) { return long (num.m_num / num.m_den); } // integer() #if 0 /// Convertidor a punto fijo inline rational::operator long() { return long (m_num / m_den); } // rational::operator long #endif bool check_ok_externo( const rational& r ); CLOSE_namespace(ADH) // ADH_port.h ==> } // namespace ADH #endif // rational_h // EOF: rational.h