Modulo [B]asico para prueba [unit]aria de programas:
|
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