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