[B]asic module for [unit] program testing:
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Defines
rational.h
Go to the documentation of this file.
00001 // rational.h   (c) 2007 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 #ifndef rational_h
00019 #define rational_h ///< Evita la inclusión múltiple
00020 
00021 /// Definido por la biblioteca C++ estándar
00022 namespace std { }
00023 
00024 #include <iostream>
00025 using namespace std;
00026 
00027 /**  La clase \c rational implementa las operaciones aritméticas
00028      principales para números rationales.
00029      - <code> [1/3] == [2/6] ==  ...   [9/27] == ... </code>
00030      - <code> [1/3]  * [2/6] / [3/9] - [9/27] </code>
00031 */
00032 template <class INT>
00033 class rational {
00034 private:
00035     INT m_num; ///< Numerador
00036     INT m_den; ///< Denominador
00037 
00038     void simplify();
00039 public:
00040     /// Constructor de vector.
00041     /// \see test_rational<NUM>::test_constructor().
00042     rational() : m_num(INT(0)), m_den(INT(1)) { }
00043     rational(INT num) : m_num(num), m_den(INT(1)) { } ///< Constructor a partir de un valor entero.
00044     rational(INT num, INT den)
00045         : m_num(num), m_den(den) { simplify(); } ///< Constructor a partir de un valor quedbrado
00046     /// Constructor de copia
00047     rational(const rational& o) { m_num = o.m_num; m_den = o.m_den; }
00048     ~rational() { }      ///< Destructor
00049 
00050     void set( const INT& n=INT(0), const INT& d=INT(1) );  // Le cambia el valor a \c "*this"
00051     /** Acceso al numerador.
00052     \dontinclude test_rational.cpp
00053     \skipline    test::num_den()
00054     \until       }}
00055     \see         test_rational<NUM>::test_num_den()
00056     */
00057     const INT& num() const { return m_num; }
00058     /// Acceso al denomirador (siempre >0).
00059     const INT& den() const { return m_den; }
00060 
00061 //  void setNum(const INT& n) { m_num=n; simplify(); }                     // FEO
00062 //  void setDen(const INT& d) { m_den= ( d!=0 ? d : m_den) ; simplify(); } // FEO
00063 
00064     rational& operator= (const rational&);  // Asignación (copia)
00065     rational& operator= (INT);
00066     rational& swap ( rational& );
00067 
00068     rational& operator+=( const rational& );
00069     rational& operator-=( const rational& );
00070     rational& operator*=( const rational& );
00071     rational& operator/=( const rational& );
00072 
00073     rational operator-() const;              // menos unario
00074 
00075     // uso NUM para no caerle encima ("shadow") a INT que es el tipo de la plantilla
00076     template <class NUM> friend rational<NUM> operator+( const rational<NUM>&, const rational<NUM>& );
00077     template <class NUM> friend rational<NUM> operator-( const rational<NUM>&, const rational<NUM>& );
00078     template <class NUM> friend rational<NUM> operator*( const rational<NUM>&, const rational<NUM>& );
00079     template <class NUM> friend rational<NUM> operator/( const rational<NUM>&, const rational<NUM>& );
00080 
00081     template <class NUM> friend bool operator==( const rational<NUM>&, const rational<NUM>& );
00082     template <class NUM> friend bool operator<(  const rational<NUM>&, const rational<NUM>& );
00083     template <class NUM> friend bool operator!=( const rational<NUM>&, const rational<NUM>& );
00084     template <class NUM> friend bool operator<=( const rational<NUM>&, const rational<NUM>& );
00085     template <class NUM> friend bool operator>=( const rational<NUM>&, const rational<NUM>& );
00086     template <class NUM> friend bool operator>(  const rational<NUM>&, const rational<NUM>& );
00087 
00088     template <class NUM> friend rational<NUM>& operator++( rational<NUM> & r );       // ++r
00089     template <class NUM> friend rational<NUM>  operator++( rational<NUM> & r , int ); // r++
00090     template <class NUM> friend rational<NUM>& operator--( rational<NUM> & r );
00091     template <class NUM> friend rational<NUM>  operator--( rational<NUM> & r , int );
00092 
00093     template <class NUM> friend ostream& operator<< (ostream &, const rational<NUM>& );
00094     template <class NUM> friend istream& operator>> (istream &,       rational<NUM>& );
00095     rational& fromString (const char* nStr);
00096 
00097     template <class NUM> friend double real   (const rational<NUM>& );   // Conversión a real
00098     template <class NUM> friend long   integer(const rational<NUM>& );   // Conversión a entero
00099 
00100     template <class NUM> friend bool check_ok( const rational<NUM>& r ); // Ok()
00101 //  excluidos porque producen ambigüedad con operadores aritméticos
00102 //  template <class NUM> operator double () { return double(m_num) / double(m_den); }
00103 //  template <class NUM> operator NUM    () { return        m_num  /        m_den ; }
00104     template <class NUM> friend class test_rational; ///< Datos de prueba para la clase.
00105 }; // rational
00106 
00107 template <class NUM>
00108 NUM mcd(NUM x, NUM y); // Calcula el Máximo Común Divisor
00109 
00110 /// Sinónimo de \c mcd(x,y).
00111 template <class INT>
00112 inline INT gcd( const INT& x, const INT& y ) { return mcd(x,y); }
00113 
00114 /** Cambia el valor del número rational a \c "n/d".
00115     \pre <code> d != 0 </code>.
00116 
00117     \dontinclude test_rational.cpp
00118     \skipline    test::set()
00119     \until       }}
00120     \see         test_rational<NUM>::test_set()
00121 */
00122 template <class INT>
00123 inline void rational<INT>::set( const INT& n, const INT& d ) {
00124     m_num = n;
00125     #ifdef NDEBUG
00126         m_den = d;
00127     #else
00128         if ( d==INT(0) ) {
00129             m_den = INT(1);
00130         }
00131         else {
00132             m_den = d;
00133         }
00134     #endif
00135     simplify();
00136 }
00137 
00138 /** Copia desde \c "o".
00139     - El valor anterior de \c "*this" se pierde.
00140 
00141     \par Complejidad:
00142          O( \c 1 )
00143     \returns *this
00144     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05
00145 
00146     \dontinclude test_rational.cpp
00147     \skipline    test::op_equal()
00148     \until       }}
00149     \see         test_rational<NUM>::test_op_equal()
00150 */
00151 template <class INT>
00152 inline rational<INT>& rational<INT>::operator=( const rational<INT>& o ) {
00153     m_num = o.m_num,
00154     m_den = o.m_den;
00155 
00156 //  sobra invocar a "simplify()" pues "o" ya está simplificado
00157     return *this;
00158 }
00159 
00160 /** Intercambia los valores de \c "*this" y \c "o".
00161       \par Complejidad:
00162          O( \c 1 )
00163     \returns *this
00164     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08
00165 
00166     \dontinclude test_rational.cpp
00167     \skipline    test::swap()
00168     \until       }}
00169     \see         test_rational<NUM>::test_swap()
00170 */
00171 template <class INT>
00172 inline rational<INT>& rational<INT>::swap( rational<INT>& o ) {
00173     #if 1
00174         rational tmp = o;
00175         o = *this;        // o.operator=( *this );
00176         *this = tmp;
00177     #else
00178         // Esto NO funciona para objetos, métodos virtuales, etc.
00179         char tmp[ sizeof( *this ) ];
00180         memcpy( tmp,  & o,   sizeof( *this ) ); // tmp = o;
00181         memcpy( & o,  this,  sizeof( *this ) ); // o = *this;
00182         memcpy( this, tmp,   sizeof( *this ) ); // *this = tmp;
00183                 // Esto violenta la integridad del Rep
00184     #endif
00185     return *this;
00186 }
00187 
00188 /** Asignación desde un \c "INT".
00189     \dontinclude test_rational.cpp
00190     \skipline    test::op_equal()
00191     \until       }}
00192     \see         test_rational<NUM>::test_op_equal()
00193 */
00194 template <class INT>
00195 inline rational<INT>& rational<INT>::operator= ( INT entero ) {
00196     m_num = entero;
00197     m_den = 1;
00198     return *this;
00199 }
00200 
00201 /** Multiplica \c "*this" por \c "num".
00202     \dontinclude test_rational.cpp
00203     \skipline    test::op_mult_equal()
00204     \until       }}
00205     \see         test_rational<NUM>::test_op_mult_equal()
00206 */
00207 template <class INT>
00208 inline rational<INT>& rational<INT>::operator*=( const rational<INT>& num ) {
00209     m_num *= num.m_num;
00210     m_den *= num.m_den;
00211     simplify();
00212     return *this;
00213 }
00214 
00215 /** Divide \c "*this" por el valor de \c "num".
00216     \pre (num != 0)
00217 
00218     \dontinclude test_rational.cpp
00219     \skipline    test::op_mult_equal()
00220     \until       }}
00221     \see         test_rational<NUM>::test_op_mult_equal()
00222 */
00223 template <class INT>
00224 inline rational<INT>& rational<INT>::operator/=( const rational<INT>& num ) {
00225     m_num *= num.m_den;
00226     m_den *= num.m_num;
00227     simplify();
00228     return *this;
00229 }
00230 
00231 /** \c "-x".
00232     - Menos unario.
00233     - Calcula y retorna el valor \c "-x".
00234 
00235     \dontinclude test_rational.cpp
00236     \skipline    test::op_minus()
00237     \until       }}
00238     \see         test_rational<NUM>::test_op_minus()
00239 */
00240 template <class INT>
00241 inline rational<INT> rational<INT>::operator-() const {
00242     rational tmp = (*this);  // tmp.rational( *this );
00243     tmp.m_num = - tmp.m_num;
00244     return tmp;
00245 }
00246 
00247 /** ¿ x == y ?.
00248     \dontinclude test_rational.cpp
00249     \skipline    test::op_comp()
00250     \until       }}
00251     \see         test_rational<NUM>::test_op_comp()
00252 */
00253 template <class NUM>
00254 inline bool operator==( const rational<NUM> &x, const rational<NUM> &y ) {
00255     return (x.m_num == y.m_num) && (x.m_den == y.m_den);
00256 /*  Nota:
00257     Como los números racionales siempre están simplificados, no puede
00258     ocurrir que [1/1] está almacenado como [3/3] y en consecuencia
00259     basta comparar los valores campo por campo para determinar si se
00260     da o no la igualdad.
00261 */
00262 }
00263 
00264 /// ¿ x < y ?
00265 template <class NUM>
00266 inline bool operator<( const rational<NUM> &x, const rational<NUM> &y ) {
00267     return (x.m_num * y.m_den) < (x.m_den * y.m_num);
00268 /*  Nota:
00269     Una desigualdad de fracciones se preserva siempre que se
00270     multiplique a ambos lados por un número positivo. Por eso:
00271             [a/b] < [c/d]          <==>
00272     (b*d) * [a/b] < [c/d] * (b*d)  <==>
00273     (b/b) * (d*a) < (b*c) * (d/d)  <==>
00274             (d*a) < (b*c)
00275 
00276     [a/b] > [c/d] <==> [(b*d)*a/b] > [(b*d)*c/d] <==> [d*a] > [b*c]
00277 
00278     Debido a que el denominador siempre es un número positivo, el
00279     trabajo de comparar 2 racionales se puede lograr haciendo 2
00280     multiplicaciones de números enteros, en lugar de convertirlos
00281     a punto flotante para hacer la división, que es hasta un orden
00282     de magnitud más lento.
00283 */
00284 //  return double(x.m_num) / double(x.m_den) < double(y.m_num) / double(y.m_den);
00285 }
00286 
00287 /// ¿ x > y ?
00288 template <class NUM>
00289 inline bool operator>( const rational<NUM> &x, const rational<NUM> &y ) {
00290     return (y < x);
00291 }
00292 
00293 /// ¿ x != y ?
00294 template <class NUM>
00295 inline bool operator!=( const rational<NUM>& x, const rational<NUM>& y ) {
00296     return !(x == y);
00297 }
00298 
00299 /// ¿ x <= y ?
00300 template <class NUM>
00301 inline bool operator<=( const rational<NUM>& x, const rational<NUM>& y ) {
00302     return !(y < x);
00303 }
00304 
00305 /// ¿ x >= y ?
00306 template <class NUM>
00307 inline bool operator>=( const rational<NUM>& x, const rational<NUM>& y ) {
00308     return !(x < y);
00309 }
00310 
00311 /// Convertidor a punto flotante.
00312 template <class NUM>
00313 inline double real(const rational<NUM>& num) {
00314     return double (num.m_num) / double (num.m_den);
00315 }
00316 
00317 /// Convertidor a punto fijo.
00318 template <class NUM>
00319 inline long integer(const rational<NUM>& num) {
00320     return long  ( num.m_num / num.m_den );
00321 }
00322 
00323 #if 0
00324     /// Convertidor a punto fijo
00325     template <class NUM>
00326     inline rational<NUM>::operator NUM() {
00327         return NUM (m_num / m_den);
00328     }
00329 #endif
00330 
00331 #include  <cstdlib>
00332 #include  <cctype>     // isdigit()
00333 
00334 /** Verifica la invariante de la clase \c rational.
00335     \par <em>Rep</em> Modelo de la clase:
00336     \code
00337     +---+
00338     | 3 | <==  m_num == numerador del número racional
00339     +---+
00340     |134| <==  m_den == denominador del número racional
00341     +---+
00342     \endcode
00343     - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep
00344 
00345     \remark
00346     Libera al programador de implementar el método \c Ok()
00347     - http://www.di-mare.com/adolfo/binder/c04.htm#sc11
00348 
00349 
00350     \dontinclude test_rational.cpp
00351     \skipline    test::check_ok()
00352     \until       }}
00353     \see         test_rational<NUM>::test_check_ok()
00354 */
00355 template <class NUM>
00356 bool check_ok( const rational<NUM>& r ) {
00357     if ( &r != 0 ) {
00358         // Ok
00359     }
00360     else {
00361         /// - Invariante: ningún objeto puede estar almacenado en la posición nula.
00362         return false;
00363     }
00364 
00365     if ( r.m_den > 0 )  {
00366         // Ok
00367     }
00368     else {
00369         /// - Invariante: el denominador debe ser un número positivo.
00370         return false;
00371     }
00372     if (r.m_num == 0) {
00373         if ( r.m_den == 1 ) {
00374             /// - Invariante: el cero debe representarse con denominador igual a "1".
00375             return true;
00376         }
00377         else {
00378             return false;
00379         }
00380     }
00381     if ( mcd(r.m_num, r.m_den) == 1 ) {
00382         // Ok
00383     }
00384     else {
00385         /// - Invariante: el numerador y el denominador deben ser primos relativos.
00386         return false;
00387     }
00388     return true;
00389 }
00390 
00391 /** Verifica la invariante de la clase \c rational.
00392     \remark
00393     Esta implementación nos se le mete al <em>Rep</em>
00394     (casi siempre no es posible implementar una función como ésta).
00395       - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep
00396     \remark
00397     Libera al programador de implementar el método \c Ok()
00398     - http://www.di-mare.com/adolfo/binder/c04.htm#sc11
00399 */
00400 template <class NUM>
00401 bool check_ok_no_Rep( const rational<NUM>& r ) {
00402     if ( ! (&r != 0) ) {
00403         /// - Invariante: ningún objeto puede estar almacenado en la posición nula.
00404         return false;
00405     }
00406 
00407     if ( ! (r.den() > 0) )  {
00408         /// - Invariante: el denominador debe ser un número positivo.
00409         return false;
00410     }
00411     if (r.num() == 0) {
00412         if ( r.den() == 1 ) {
00413             /// - Invariante: el cero debe representarse con denominador igual a "1".
00414             return true;
00415         }
00416         else {
00417             return false;
00418         }
00419     }
00420     if ( ! ( mcd(r.num(), r.den()) == 1 ) ) {
00421         /// - Invariante: el numerador y el denominador deben ser primos relativos.
00422         return false;
00423     }
00424     return true;
00425 }
00426 
00427 /** Calcula el Máximo Común Divisor de los números \c "x" y \c "y".
00428     - <code> mcd(x,y) >= 1 </code> siempre.
00429     - MCD <==> GCD: <em> Greatest Common Divisor </em>.
00430 
00431     \pre
00432     <code> (y != 0) </code>
00433 
00434     \remark
00435     Se usa el algoritmo de Euclides para hacer el cálculo.
00436 
00437     \par Ejemplo:
00438     \code
00439     2*3*5 == mcd( 2*2*2*2 * 3*3 * 5*5, 2*3*5 )
00440        30 == mcd( -3600, -30 )
00441     \endcode
00442 
00443     \dontinclude test_rational.cpp
00444     \skipline    test::mcd()
00445     \until       }}
00446     \see         test_rational<NUM>::test_mcd()
00447 */
00448 template <class NUM>
00449 NUM mcd(NUM x, NUM y) {
00450     NUM g = (x < 0 ? -x : x); // trabaja con valores positivos
00451     NUM r = (y < 0 ? -y : y); // "r" es el resto
00452     NUM temp;
00453 
00454     do {
00455         temp = r;
00456         r    = g % r;
00457         g    = temp;
00458     } while (NUM(0) != r);
00459 
00460     return g;
00461 }
00462 
00463 /** Simplifica el numerador y el denomidador.
00464     - Transforma el número rational de manera que el numerador y el
00465       denominador sean primos relativos, asegurando además que el
00466       denominador es siempre positivo.
00467     - Si <code>(m_num==0) ==> (m_den==1)</code>.
00468     - Simplifica la fracción para que \c m_num y \c m_den sean números
00469       primos relativos ie, <code>mcd(m_num,m_den) == 1</code>.
00470     - Asegura que \c m_den sea un número positivo.
00471     - Restaura la invariante de la clase \c rational.
00472 
00473     \dontinclude test_rational.cpp
00474     \skipline    test::simplify()
00475     \until       }}
00476     \see         test_rational<NUM>::test_simplify()
00477 */
00478 template <class NUM>
00479 void rational<NUM>::simplify() {
00480     if (m_num == 0) {
00481        m_den = 1;
00482            return;
00483     }
00484     NUM divisor = mcd(m_num, m_den);
00485     if (divisor > 1) {   // ==> (divisor != 0)
00486         m_num /= divisor;
00487         m_den /= divisor;
00488     }
00489     if (m_den < 0) {
00490         m_num = -m_num;
00491         m_den = -m_den;
00492     }
00493 }
00494 
00495 /** Le suma a \c "*this" el valor de \c "otro".
00496     \dontinclude test_rational.cpp
00497     \skipline    test::op_add_equal()
00498     \until       }}
00499     \see         test_rational<NUM>::test_op_add_equal()
00500 */
00501 template <class INT>
00502 rational<INT>& rational<INT>::operator+=( const rational<INT>& otro ) {
00503     m_num  = m_num * otro.m_den + m_den * otro.m_num;
00504     m_den *= otro.m_den;
00505     simplify();
00506     return *this;
00507 }
00508 
00509 /** Le resta a \c "*this" el valor de \c "otro".
00510     \dontinclude test_rational.cpp
00511     \skipline    test::op_add_equal()
00512     \until       }}
00513     \see         test_rational<NUM>::test_op_add_equal()
00514 */
00515 template <class INT>
00516 rational<INT>& rational<INT>::operator-=( const rational<INT>& otro ) {
00517     INT oldm_den = m_den;
00518     INT oldm_num = m_num;
00519     INT d       = otro.m_den;
00520     INT n       = otro.m_num;
00521 
00522     m_den *= d;
00523     m_num = oldm_num * d - oldm_den * n;
00524     simplify();
00525 
00526     return *this;
00527 }
00528 
00529 /** Graba el valor de \c "r" en el flujo \c "COUT".
00530     - Graba el valor en el formato [num/den].
00531     - En particular, este es el operador que se invoca
00532       cuando se usa, por ejemplo, este tipo de instrucción:
00533      \code
00534           cout << r << q;
00535      \endcode
00536 
00537     \dontinclude test_rational.cpp
00538     \skipline    test::op_out()
00539     \until       }}
00540     \see         test_rational<NUM>::test_op_out()
00541 */
00542 template <class NUM>
00543 ostream& operator<<( ostream &COUT, const rational<NUM>& r ) {
00544     if ( r.m_den == 1 ) { // no hay parte fraccional
00545         return COUT << "[" << r.m_num << "]" ;
00546     } else {
00547         return COUT << "[" << r.m_num << "/" << r.m_den << "]" ;
00548     }
00549 }
00550 
00551 /** Lee del flujo de texto \c "CIN" el valor de \c "r".
00552     \pre
00553     El número rational debe haber sido escrito usando
00554     el formato "[r/den]", aunque es permisible usar
00555     algunos blancos.
00556     - Se termina de leer el valor sólo cuando encuentra \c "]".
00557     - <code> [ -+-+-+-+- 4 / -- -+ -- 32  ] </code> se lee como
00558       <code> [1/8] </code>
00559 
00560     \dontinclude test_rational.cpp
00561     \skipline    test::op_in()
00562     \until       }}
00563     \see         test_rational<NUM>::test_op_in()
00564 */
00565 template <class NUM>
00566 istream& operator>>( istream &CIN, rational<NUM>& r ) {
00567     char ch;  // valor leido, letra por letra, de "CIN"
00568     const NUM DIEZ = 10;
00569 
00570     bool es_positivo = true;    // manejo de los signos + y -
00571 
00572     // se brinca todo hasta el primer dígito
00573     do {
00574         CIN >> ch;
00575         if (ch == '-') {  // cambia de signo
00576             es_positivo = !es_positivo;
00577         }
00578     } while (!isdigit(ch));
00579 
00580     // se traga el numerador
00581     r.m_num = 0;
00582     while (isdigit(ch)) { // convierte a GranNum: izq --> der
00583         r.m_num = DIEZ * r.m_num + (ch-'0');
00584         CIN >> ch;
00585     }
00586 
00587     // se brinca los blancos después del numerador
00588     while (isspace(ch)) {
00589         CIN >> ch;
00590     }
00591 
00592     if (ch ==']') { // es un número entero
00593         r.m_den = 1;
00594     }
00595     else {
00596         do {  // se brinca todo hasta el denominador
00597             CIN >> ch;
00598             if (ch == '-') {
00599                 es_positivo = !es_positivo;
00600             }
00601         } while (!isdigit(ch));
00602 
00603         // se traga el denominador
00604         r.m_den = 0;
00605         while (isdigit(ch)) {
00606             r.m_den = DIEZ * r.m_den + (ch-'0');
00607             CIN >> ch;
00608         }
00609 
00610         // El programa se duerme si en el flujo de entrada
00611         // NO aparece el caracter delimitador final "]",
00612         // pues la lectura termina hasta encontrar el "]".
00613         while (ch != ']') {
00614             CIN >> ch;
00615         }
00616     }   // corrección: Andrés Arias <e980300@anubis.ecci.ucr.ac.cr>
00617 
00618 
00619     // le cambia el signo, si hace falta
00620     if (! es_positivo) {
00621         r.m_num = -r.m_num;
00622     }
00623     #ifndef NDEBUG
00624         if ( r.m_den == NUM(0) ) {
00625             r.m_den = 1;
00626         }
00627     #endif
00628 
00629     r.simplify();
00630     return CIN;
00631 /*
00632     no detecta errores...
00633     [1/0] lo lee y no se queja
00634     [ !#!#!$#@! 3/ aaaa 4  jajaja ] lo lee como [3/4]
00635     ... pero no se supone que el usuario cometa errores...
00636 */
00637 }
00638 
00639 /** Establece el varlor de \c "*this" a partir de la hilera \c "nStr".
00640     \pre \c "nStr" debe estar escrita en el formato "[num/den]".
00641 
00642     \dontinclude test_rational.cpp
00643     \skipline    test::fromString()
00644     \until       }}
00645     \see         test_rational<NUM>::test_fromString()
00646 */
00647 template <class NUM>
00648 rational<NUM>& rational<NUM>::fromString (const char* nStr) {
00649     char ch;  // valor obtenido, caracter por caracter, de "nStr"
00650     const NUM DIEZ = NUM(10);
00651 
00652     bool es_positivo = true;    // manejo de los signos + y -
00653 
00654     // se brinca todo hasta el primer dígito
00655     do {
00656         ch = *nStr; nStr++;
00657         if (ch == '-') {  // cambia de signo
00658             es_positivo = !es_positivo;
00659         }
00660     } while (!isdigit(ch));
00661 
00662     // se traga el numerador
00663     NUM num = NUM(0);
00664     while (isdigit(ch)) { // convierte a <NUM>: izq --> der
00665         num = DIEZ * num + NUM(ch-'0');
00666         ch = *nStr; nStr++;
00667     }
00668 
00669     // se brinca los blancos después del numerador
00670     while (isspace(ch)) {
00671         ch = *nStr; nStr++;
00672     }
00673 
00674     NUM den;
00675     if (ch ==']') { // es un número entero
00676         den = NUM(1);
00677     }
00678     else {
00679         do {  // se brinca todo hasta el denominador
00680             ch = *nStr; nStr++;
00681             if (ch == '-') {
00682                 es_positivo = !es_positivo;
00683             }
00684         } while (!isdigit(ch));
00685 
00686         // se traga el denominador
00687         den = NUM(0);
00688         while (isdigit(ch)) {
00689             den = DIEZ * den + NUM(ch-'0');
00690             ch = *nStr; nStr++;
00691         }
00692         // Ya no importa si aparece o no el ']' del final del número
00693     }
00694 
00695     // le cambia el signo, si hace falta
00696     if (! es_positivo) {
00697         num = -num;
00698     }
00699     set( num, den );
00700     return *this;
00701 }
00702 
00703 /** \c "x+y".
00704     - Calcula y retorna la suma \c "x+y".
00705 
00706     \dontinclude test_rational.cpp
00707     \skipline    test::op_add()
00708     \until       }}
00709     \see         test_rational<NUM>::test_op_add()
00710 */
00711 template <class NUM>
00712 rational<NUM> operator + (const rational<NUM> &x, const rational<NUM> &y) {
00713     NUM res_num, res_den;
00714     res_den = x.m_den * y.m_den;
00715     res_num = x.m_num * y.m_den + x.m_den * y.m_num;
00716 
00717     return rational<NUM>(res_num, res_den);
00718 }
00719 
00720 /** \c "x-y".
00721     - Calcula y retorna la resta \c "x-y".
00722 
00723     \dontinclude test_rational.cpp
00724     \skipline    test::op_add()
00725     \until       }}
00726     \see         test_rational<NUM>::test_op_add()
00727 */
00728 template <class NUM>
00729 rational<NUM> operator-( const rational<NUM> &x, const rational<NUM> &y ) {
00730     NUM res_num, res_den;
00731     res_den = x.m_den * y.m_den;
00732     res_num = x.m_num * y.m_den - x.m_den * y.m_num;
00733 
00734     return rational<NUM>(res_num, res_den);
00735 }
00736 
00737 /** \c "x*y".
00738     - Calcula y retorna la multiplicación \c "x*y".
00739 
00740     \dontinclude test_rational.cpp
00741     \skipline    test::op_mult()
00742     \until       }}
00743     \see         test_rational<NUM>::test_op_mult()
00744 */
00745 template <class NUM>
00746 rational<NUM> operator*( const rational<NUM> &x, const rational<NUM> &y ) {
00747     NUM res_num, res_den;
00748     res_num = x.m_num * y.m_num;
00749     res_den = x.m_den * y.m_den;
00750 
00751     return rational<NUM>(res_num, res_den);
00752 }
00753 
00754 /** \c "x/y".
00755     - Calcula y retorna la división \c "x/y".
00756 
00757     \pre <code> y != 0 </code>
00758     \dontinclude test_rational.cpp
00759     \skipline    test::op_mult()
00760     \until       }}
00761     \see         test_rational<NUM>::test_op_mult()
00762 */
00763 template <class NUM>
00764 rational<NUM> operator/( const rational<NUM> &x, const rational<NUM> &y ) {
00765     NUM res_num, res_den;
00766     #ifdef NDEBUG
00767         res_num = x.m_num * y.m_den;
00768         res_den = x.m_den * y.m_num;
00769         return rational<NUM>(res_num, res_den);
00770     #else
00771         if (NUM(0) != y.m_num) {
00772             res_num = x.m_num * y.m_den;
00773             res_den = x.m_den * y.m_num;
00774             return rational<NUM>(res_num, res_den);
00775         }
00776         else {
00777             return rational<NUM>(NUM(0),NUM(1));
00778         }
00779     #endif
00780 }
00781 
00782 /** \c ++r.
00783     \dontinclude test_rational.cpp
00784     \skipline    test::op_cpp()
00785     \until       }}
00786     \see         test_rational<NUM>::test_op_cpp()
00787 */
00788 template <class NUM>
00789 inline rational<NUM>& operator++( rational<NUM> & r ) {
00790     r.m_num += r.m_den;
00791     return r;
00792 }
00793 
00794 /// \c r++.
00795 template <class NUM>
00796 inline rational<NUM> operator++( rational<NUM> & r , int ) {
00797     rational<NUM> tmp = r;
00798     r.m_num += r.m_den;
00799     return tmp;
00800 }
00801 
00802 /** \c --r.
00803     \dontinclude test_rational.cpp
00804     \skipline    test::op_cpp()
00805     \until       }}
00806     \see         test_rational<NUM>::test_op_cpp()
00807 */
00808 template <class NUM>
00809 inline rational<NUM>& operator--( rational<NUM> & r ) {
00810     r.m_num -= r.m_den;
00811     return r;
00812 }
00813 
00814 /// \c r--.
00815 template <class NUM>
00816 inline rational<NUM> operator--( rational<NUM> & r , int ) {
00817     rational<NUM> tmp = r;
00818     r.m_num -= r.m_den;
00819     return tmp;
00820 }
00821 
00822 #endif // rational_h
00823 
00824 // EOF: rational.h