rational.h

Ir a la documentación de este archivo.
00001 // rational.h   (c) 2005 adolfo@di-mare.com
00002 
00003 /** \file  rational.h
00004     \brief Declara el tipo \c "rational".
00005     - La clase \c rational implementa las operaciones aritméticas
00006       principales para números rationales.
00007 
00008     - <code> [1/3] == [2/6] ==  ...   [9/27] == ... </code>
00009     - <code> [1/3]  * [2/6] / [3/9] - [9/27] </code>
00010 
00011     - Permite usar racionales en cualquier sitio en donde se puedan
00012       usar valores numéricos.
00013 
00014     \author Adolfo Di Mare <adolfo@di-mare.com>
00015     \date   2005
00016 */
00017 
00018 
00019 #ifndef rational_h
00020 #define rational_h ///< Evita la inclusión múltiple
00021 
00022 #define  INCLUDE_iostream // ADH_port.h ==> #include <iostream>
00023 #include "ADH_port.h"
00024 
00025 OPEN_namespace(ADH)       // ADH_port.h ==> namespace ADH {
00026 USING_namespace(ADH);     // ADH_port.h ==> using namespace ADH;
00027 
00028 /**  La clase \c rational implementa las operaciones aritméticas
00029      principales para números rationales.
00030      - <code> [1/3] == [2/6] ==  ...   [9/27] == ... </code>
00031      - <code> [1/3]  * [2/6] / [3/9] - [9/27] </code>
00032 */
00033 class rational {
00034 private:
00035     long m_num; ///< Numerador
00036     long m_den; ///< Denominador
00037 
00038     void Simplify();
00039 
00040 public:
00041     // constructores
00042     rational() : m_num(0), m_den(1) { }  ///< Constructor de vector
00043     rational(long num) : m_num(num), m_den(1) { } ///< Constructor a partir de un valor entero
00044     rational(long num, long den)
00045         : m_num(num), m_den(den) { Simplify(); } ///< Constructor a partir de un valor quedbrado
00046     rational(const rational& o)       /// Constructor de copia
00047         { m_num = o.m_num, m_den = o.m_den; }
00048     ~rational() { }      ///< Destructor
00049 
00050     void set(long num=0, long den=1);  // Le cambia el valor a \c "*this"
00051 
00052     long num() const { return m_num; }  ///< Copia del numerador
00053     long den() const { return m_den; }  ///< Copia del denominador
00054 
00055 //  void num(long n) { m_num=n; Simplify(); }  // FEO
00056 //  void den(long d) { m_den= ( d!=0 ? d : m_den) ; Simplify(); }  // FEO
00057 
00058     rational& operator  = (const rational&);  // Asignación (copia)
00059     rational& operator  = (long);
00060     rational& swap ( rational& );
00061 
00062     rational& operator += (const rational&);
00063     rational& operator -= (const rational&);
00064 //  rational& operator *= (const rational&);
00065     rational& operator /= (const rational&);
00066 
00067     rational operator  - () const;              // menos unario
00068 
00069     friend rational operator + (const rational&, const rational&);
00070     friend rational operator - (const rational&, const rational&);
00071     friend rational operator * (const rational&, const rational&);
00072     friend rational operator / (const rational&, const rational&);
00073 
00074     friend bool operator == (const rational&, const rational&);
00075     friend bool operator <  (const rational&, const rational&);
00076     friend bool operator != (const rational&, const rational&);
00077     friend bool operator <= (const rational&, const rational&);
00078     friend bool operator >= (const rational&, const rational&);
00079     friend bool operator >  (const rational&, const rational&);
00080 
00081     friend std::ostream& operator << (std::ostream &, const rational& );
00082     friend std::istream& operator >> (std::istream &,       rational& );
00083     rational& fromString (const char* nStr);
00084 
00085     friend double real   (const rational& );   // Conversión a real
00086     friend long   integer(const rational& );   // Conversión a long
00087 
00088     friend bool check_ok( const rational& r ); // Ok()
00089 //  excluidos porque producen ambigüedad con operadores aritméticos
00090 //  operator double () { return double(m_num) / double(m_den); }
00091 //  operator long   () { return        m_num  /        m_den ; }
00092 }; // rational
00093 
00094 long mcd(long x, long y); // Calcula el Máximo Común Divisor
00095 
00096 /// Sinónimo de \c mcd(x,y) <code> [ inline ] </code>
00097 inline long gcd(long x, long y) { return mcd(x,y); }
00098 
00099 /// Cambia el valor del número rational a \c "n/d"
00100 inline void rational::set(long n, long d) {
00101     m_num = n;
00102     m_den = d;
00103     Simplify();
00104 }
00105 
00106 /** Copia desde \c "o".
00107     - El valor anterior de \c "*this" se pierde.
00108     \par Complejidad:
00109          O( \c 1 )
00110     \returns *this
00111     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05
00112 */
00113 inline rational& rational::operator = (const rational& o) {
00114     m_num = o.m_num,
00115     m_den = o.m_den;
00116 
00117 //  sobra invocar a "Simplify()" pues "o" ya está simplificado
00118     return *this;
00119 }  // operator =
00120 
00121 /** Intercambia los valores de \c "*this" y \c "o".
00122       \par Complejidad:
00123          O( \c 1 )
00124 
00125     \returns *this
00126 
00127     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08
00128 */
00129 inline rational& rational::swap ( rational& o ) {
00130     #if 1
00131         rational tmp = o;
00132         o = *this;        // o.operator=( *this );
00133         *this = tmp;
00134     #else
00135         // Esto NO funciona para objetos, m‚todos virtuales, etc.
00136         char tmp[ sizeof( *this ) ];
00137         memcpy( tmp,  & o,   sizeof( *this ) ); // tmp = o;
00138         memcpy( & o,  this,  sizeof( *this ) ); // o = *this;
00139         memcpy( this, tmp,   sizeof( *this ) ); // *this = tmp;
00140     #endif
00141     return *this;
00142 }
00143 
00144 /// Asignación desde un \c "long".
00145 inline rational& rational::operator = (long entero) {
00146     m_num = entero;
00147     m_den = 1;
00148     return *this;
00149 }  // operator =
00150 
00151 
00152 #if 0
00153 /// Multiplica \c "*this" por \c "num".
00154 inline rational& rational::operator *= (const rational& num) {
00155     m_num *= num.m_num;
00156     m_den *= num.m_den;
00157     Simplify();
00158     return *this;
00159 }  // operator *=
00160 #endif
00161 
00162 rational & operator *= ( rational & a, const rational & b );
00163 
00164 /**  Divide \c "*this" por el valor de \c "num".
00165     \pre
00166     - (num != 0)
00167 */
00168 inline rational& rational::operator /= (const rational& num) {
00169     m_num *= num.m_den;
00170     m_den *= num.m_num;
00171     Simplify();
00172     return *this;
00173 }  // operator /=
00174 
00175 /// \c "-x".
00176 /// - Menos unario
00177 /// - Calcula y retorna el valor \c "-x"
00178 inline rational rational::operator - () const {
00179     rational tmp = (*this);  // tmp.rational( *this );
00180     tmp.m_num = - tmp.m_num;
00181     return tmp;
00182 }  // operator -
00183 
00184 /// ¿ x == y ?
00185 inline bool operator == (const rational &x, const rational &y) {
00186     return (x.m_num == y.m_num) && (x.m_den == y.m_den);
00187 /*  Nota:
00188     Como los números racionales siempre están simplificados, no puede
00189     ocurrir que [1/1] está almacenado como [3/3] y en consecuencia
00190     basta comparar los valores campo por campo para determinar si se
00191     da o no la igualdad.
00192 */
00193 }  // operator ==
00194 
00195 /// ¿ x < y ?
00196 inline bool operator < (const rational &x, const rational &y) {
00197     return (x.m_num * y.m_den) < (x.m_den * y.m_num);
00198 /*  Nota:
00199     Una desigualdad de fracciones se preserva siempre que se 
00200     multiplique a ambos lados por un número positivo. Por eso:
00201           [a/b] <       [c/d]   <==>
00202     [(b*d)*a/b] < [(b*d)*c/d]   <==>
00203           [d*a] < [b*c]
00204 
00205     [a/b] > [c/d] <==> [(b*d)*a/b] > [(b*d)*c/d] <==> [d*a] > [b*c]
00206 
00207     Debido a que el denominador siempre es un número positivo, el
00208     trabajo de comparar 2 racionales se puede lograr haciendo 2
00209     multiplicaciones de números enteros, en lugar de convertirlos
00210     a punto flotante para hacer la división, que es hasta un orden
00211     de magnitud más lento.
00212 */
00213 //  return double(x.m_num) / double(x.m_den) < double(y.m_num) / double(y.m_den);
00214 }  // operator <
00215 
00216 /// ¿ x > y ?
00217 inline bool operator > (const rational &x, const rational &y) {
00218     return (y < x);
00219 }  // operator >
00220 
00221 /// ¿ x != y ?
00222 inline bool operator != (const rational& x, const rational& y) {
00223     return !(x == y);
00224 }  // operator !=
00225 
00226 /// ¿ x <= y ?
00227 inline bool operator <= (const rational& x, const rational& y) {
00228     return !(y < x);
00229 }  // operator <=
00230 
00231 /// ¿ x >= y ?
00232 inline bool operator >= (const rational& x, const rational& y) {
00233     return !(x < y);
00234 }  // operator >=
00235 
00236 /// Convertidor a punto flotante.
00237 inline double real(const rational& num) {
00238     return double (num.m_num) / double (num.m_den);
00239 } // real()
00240 
00241 /// Convertidor a punto fijo.
00242 inline long integer(const rational& num) {
00243     return long   (num.m_num /          num.m_den);
00244 } // integer()
00245 
00246 #if 0
00247     /// Convertidor a punto fijo
00248     inline rational::operator long() {
00249         return long (m_num / m_den);
00250     }  // rational::operator long
00251 #endif
00252 
00253 bool check_ok_externo( const rational& r );
00254 
00255 CLOSE_namespace(ADH)      // ADH_port.h ==> } // namespace ADH
00256 
00257 #endif // rational_h
00258 
00259 // EOF: rational.h

Generado el Wed Apr 9 13:16:23 2008 para Prueba de la clase rational: por  doxygen 1.5.4