rational.cpp

Ir a la documentación de este archivo.
00001 // rational.cpp        (c) 2005 [email protected]
00002 
00003 /** \file  rational.cpp
00004     \brief Implementaciones para la clase \c "rational"
00005 
00006     \author Adolfo Di Mare <[email protected]>
00007     \date   2005
00008 
00009     - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
00010 */
00011 
00012 #include "rational.h"
00013 #include  <cstdlib>
00014 #include  <cctype>     // isdigit()
00015 
00016 OPEN_namespace(ADH)
00017 USING_namespace(ADH);
00018 
00019 #ifndef   NDEBUG
00020     #include "check_ok.cpp" // invariante de la clase
00021 #endif // NDEBUG
00022 
00023 /** Calcula el Máximo Común Divisor de los números \c "x" y \c "y".
00024     - <code> mcd(x,y) >= 1 </code> siempre.
00025     - MCD <==> GCD: <em> Greatest Common Divisor </em>.
00026 
00027     \pre
00028     <code> (y != 0) </code>
00029 
00030     \remark
00031     Se usa el algoritmo de Euclides para hacer el cálculo.
00032 
00033     \par Ejemplo:
00034     \code
00035     2*3*5 == mcd( 2*2*2*2 * 3*3 * 5*5, 2*3*5 )
00036        30 == mcd( -3600, -30 )
00037     \endcode
00038 */
00039 long mcd(long x, long y) {
00040     long g = (x < 0 ? -x : x);
00041     long r = (y < 0 ? -y : y);
00042     long temp;
00043 
00044     do {
00045         temp = r;
00046         r    = g % r;
00047         g    = temp;
00048     } while (0 != r);
00049 
00050     return g;
00051 }  // mcd()
00052 
00053 
00054 /** - Simplifica el numerador y el denomidador.
00055     - Transforma el número rational de manera que el numerador y el
00056       denominador sean primos relativos, asegurando además que el
00057       denominador es siempre positivo.
00058     - Si <code>(m_num==0) ==> (m_den==1)</code>.
00059     - Simplifica la fracción para que \c m_num y \c m_den sean números
00060       primos relativos ie, <code>mcd(m_num,m_den) == 1</code>.
00061     - Asegura que \c m_den sea un número positivo.
00062     - Restaura la invariante de la clase \c rational.
00063 */
00064 void rational::Simplify() {
00065     if (m_num == 0) {
00066        m_den = 1;
00067     }
00068     long divisor = mcd(m_num, m_den);
00069     if (divisor > 1) {   // ==> (divisor != 0)
00070         m_num /= divisor;
00071         m_den /= divisor;
00072     }
00073     if (m_den < 0) {
00074         m_num = -m_num;
00075         m_den = -m_den;
00076     }
00077 }  // rational::Simplify()
00078 
00079 /// Le suma a \c "*this" el valor de \c "otro"
00080 rational& rational::operator += (const rational& otro) {
00081     m_num  = m_num * otro.m_den + m_den * otro.m_num;
00082     m_den *= otro.m_den;
00083     Simplify();
00084 
00085     return *this;
00086 }  // operator +=
00087 
00088 
00089 /// Le resta a \c "*this" el valor de \c "otro"
00090 rational& rational::operator -= (const rational& num) {
00091     long oldm_den = m_den;
00092     long oldm_num = m_num;
00093     long d       = num.m_den;
00094     long n       = num.m_num;
00095 
00096     m_den *= d;
00097     m_num = oldm_num * d - oldm_den * n;
00098     Simplify();
00099 
00100     return *this;
00101 }  // operator -=
00102 
00103 /// Establece el varlor de \c "*this" a partir de la hilera \c "nStr"
00104 /// \pre \c "nStr" debe estar escrita en el formato "[num/den]".
00105 rational& rational::fromString (const char* nStr) {
00106     char ch;  // valor obtenido, letra por letra, de "num"
00107 
00108     bool es_positivo = true;    // manejo de los signos + y -
00109 
00110     // se brinca todo hasta el primer dígito
00111     do {
00112         ch = *nStr; nStr++;
00113         if (ch == '-') {  // cambia de signo
00114             es_positivo = !es_positivo;
00115         }
00116     } while (!isdigit(ch));
00117 
00118     // se traga el numerador
00119     long num = 0;
00120     while (isdigit(ch)) { // convierte a decimal: izq --> der
00121         num = 10 * num + (ch-'0');
00122         ch = *nStr; nStr++;
00123     }
00124 
00125     // se brinca los blancos después del numerador
00126     while (isspace(ch)) {
00127         ch = *nStr; nStr++;
00128     }
00129 
00130     long den;
00131     if (ch ==']') { // es un número entero
00132         den = 1;
00133     }
00134     else {
00135         do {  // se brinca todo hasta el denominador
00136             ch = *nStr; nStr++;
00137             if (ch == '-') {
00138                 es_positivo = !es_positivo;
00139             }
00140         } while (!isdigit(ch));
00141 
00142         // se traga el denominador
00143         den = 0;
00144         while (isdigit(ch)) {
00145             den = 10 * den + (ch-'0');
00146             ch = *nStr; nStr++;
00147         }
00148         // Ya no importa si aparece o no el ']' del final del número
00149     }
00150 
00151 
00152     // le cambia el signo, si hace falta
00153     if (! es_positivo) {
00154         num = -num;
00155     }
00156     set( num, den );
00157     return *this;
00158 }
00159 
00160 /** Graba el valor de \c "r" en el flujo \c "COUT"
00161 
00162     - Graba el valor en el formato [num/den].
00163 
00164     - En particular, este es el operador que se invoca
00165       cuando se usa, por ejemplo, este tipo de instrucción:
00166      \code
00167           cout << r << q;
00168      \endcode
00169 */
00170 ostream& operator<< (ostream &COUT, const rational& r) {
00171     if ( r.m_den == 1 ) { // no hay parte fraccional
00172         return COUT << "[" << r.m_num << "]" ;
00173     } else {
00174         return COUT << "[" << r.m_num << "/" << r.m_den << "]" ;
00175     }
00176 }  // operator <<
00177 
00178 /** Lee del flujo de texto \c "CIN" el valor de \c "r"
00179 
00180     \pre
00181     El número rational debe haber sido escrito usando
00182     el formato "[r/den]", aunque es permisible usar
00183     algunos blancos.
00184     - Se termina de leer el valor sólo cuando encuentra \c "]".
00185     - <code> [ -+-+-+-+- 4 / -- -+ -- 32  ] </code> se lee como
00186       <code> [1/8] </code>
00187 */
00188 istream& operator >> (istream &CIN, rational& r) {
00189     char ch;  // valor leido, letra por letra, de "CIN"
00190 
00191     bool es_positivo = true;    // manejo de los signos + y -
00192 
00193     // se brinca todo hasta el primer dígito
00194     do {
00195         CIN >> ch;
00196         if (ch == '-') {  // cambia de signo
00197             es_positivo = !es_positivo;
00198         }
00199     } while (!isdigit(ch));
00200 
00201     // se traga el numerador
00202     r.m_num = 0;
00203     while (isdigit(ch)) { // convierte a decimal: izq --> der
00204         r.m_num = 10 * r.m_num + (ch-'0');
00205         CIN >> ch;
00206     }
00207 
00208     // se brinca los blancos después del numerador
00209     while (isspace(ch)) {
00210         CIN >> ch;
00211     }
00212 
00213     if (ch ==']') { // es un número entero
00214         r.m_den = 1;
00215     }
00216     else {
00217         do {  // se brinca todo hasta el denominador
00218             CIN >> ch;
00219             if (ch == '-') {
00220                 es_positivo = !es_positivo;
00221             }
00222         } while (!isdigit(ch));
00223 
00224         // se traga el denominador
00225         r.m_den = 0;
00226         while (isdigit(ch)) {
00227             r.m_den = 10 * r.m_den + (ch-'0');
00228             CIN >> ch;
00229         }
00230 
00231         // El programa se duerme si en el flujo de entrada
00232         // NO aparece el caracter delimitador final "]",
00233         // pues la lectura termina hasta encontrar el "]".
00234         while (ch != ']') {
00235             CIN >> ch;
00236         }
00237     }   // corrección: Andrés Arias <[email protected]>
00238 
00239 
00240     // le cambia el signo, si hace falta
00241     if (! es_positivo) {
00242         r.m_num = -r.m_num;
00243     }
00244 
00245     r.Simplify();
00246     return CIN;
00247 /*
00248     no detecta errores...
00249     [1/0] lo lee y no se queja
00250     [ !#!#!$#@! 3/ aaaa 4  jajaja ] lo lee como 3/4
00251     ... pero no se supone que el usuario cometa errores...
00252 */
00253 
00254 }  // operator >>
00255 
00256 /// \c "x+y"
00257 ///
00258 /// - Calcula y retorna la suma \c "x+y"
00259 rational operator + (const rational &x, const rational &y) {
00260     long res_num, res_den;
00261     res_den = x.m_den * y.m_den;
00262     res_num = x.m_num * y.m_den + x.m_den * y.m_num;
00263 
00264     return rational(res_num, res_den);
00265 }  // operator + ()
00266 
00267 /// \c "x-y"
00268 ///
00269 /// - Calcula y retorna la resta \c "x-y"
00270 rational operator - (const rational &x, const rational &y) {
00271     long res_num, res_den;
00272 
00273     res_den = x.m_den * y.m_den;
00274     res_num = x.m_num * y.m_den - x.m_den * y.m_num;
00275 
00276     return rational(res_num, res_den);
00277 }  // operator - ()
00278 
00279 /// \c "x*y"
00280 ///
00281 /// - Calcula y retorna la multiplicación \c "x*y"
00282 rational operator * (const rational &x, const rational &y) {
00283     long res_num, res_den;
00284 
00285     res_num = x.m_num * y.m_num;
00286     res_den = x.m_den * y.m_den;
00287 
00288     return rational(res_num, res_den);
00289 }  // operator * ()
00290 
00291 /// \c "x/y"
00292 ///
00293 /// - Calcula y retorna la división \c "x/y"
00294 ///
00295 /// \pre <code> y != 0 </code>
00296 rational operator / (const rational &x, const rational &y) {
00297     long res_num, res_den;
00298     if (0 != y.m_num) {
00299         res_num = x.m_num * y.m_den;
00300         res_den = x.m_den * y.m_num;
00301     }
00302     return rational(res_num, res_den);
00303 }  // operator / ()
00304 
00305 CLOSE_namespace(ADH)
00306 
00307 // EOF: rational.cpp

Generado el Mon Sep 11 00:19:12 2006 para Herencia Ordenada: por  doxygen 1.4.7
Hosted by www.Geocities.ws

1