Universidad de Costa Rica
Ciencias de

Curso:
Programación II
Documentación
IV Tarea Programada
Profesor: Adolfo Di-Mare
Alumnos:
Elsie Castro Villalobos A41369
Armando Soto Rodríguez A55609
20/09/2007
Índice
Dirección
Internet en dónde está la documentación:
Descripción
del problema a resolver:
Especificación
de la clase Decimal:
Especificación
de las clases de prueba:
Invariante de
la clase Decimal:
Formato de los
datos de prueba
Entradas vs
Salidas esperadas:
El
siguiente trabajo se basa en la implementación de una nueva clase llamada Decimal,
en la cual se pondrá en práctica la reutilización de código. Esta clase deberá
contar al menos con los operadores básicos esenciales los cuales son: suma,
resta, multiplicación, división y modulo, para que así pueda funcionar con la
clase test_rational.
http://www.geocities.com/elsiecv21/Documentacion4.htm
http://www.geocities.com/arsoro1986/Tarea4.htm
Implementar la clase Decimal que cuenta con las operaciones aritméticas
necesarias para que funcione correctamente con el programa de prueba para la
clase emplantillada
de números racionales. En el Rep de la
clase Decimal usar una representación de los dígitos decimales lo cual permita
almacenar tantos dígitos como sea necesario.
El
objetivo de esta tarea es la de reutilización de código, y teniendo este como
base implementar una nueva clase, con el fin de ahorrar tiempo y hacer más fácil
la implementación de un programa.
La
clase decimal sirve para almacenar enteros de cualquier tamaño y así poder
realizar operaciones matemáticas básicas con los mismos; suma, resta
multiplicación, división y modulo.
Para
implementarla se reutilizó la clase BigNum y así
poder realizar fácilmente los operadores aritméticos y los operadores de
comparación.
Clase
Rational:
void set(INT num=0, INT den=1)
Le cambia el valor a *this
INT num() const { return m_num; }
Copia del numerador
INT den() const { return m_den; }
Copia del denominador
rational& operator = (const
rational&): Asignación
de copia; copia desde "o", el valor anterior de "*this" se
pierde.
rational& operator = (INT): Asignación
desde un "long".
rational& swap ( rational& ): Intercambia los valores de "*this" y "o".
rational& operator +=
(const rational&): Le suma a "*this" el valor de "otro".
rational& operator -= (const rational&): Le resta a "*this" el valor de "otro".
rational& operator *=
(const rational&): Multiplica "*this" por "num".
rational& operator /=
(const rational&): Divide "*this" por el valor de "num".
rational operator - () const: Calcula y retorna el valor "-x".
friend rational<T> operator +
(const rational<T>&, const rational<T>&): Calcula y retorna la suma "x+y".
friend rational<T> operator -
(const rational<T>&, const rational<T>&): Calcula y retorna la resta "x-y".
friend rational<T> operator *
(const rational<T>&, const rational<T>&): Calcula y retorna la multiplicación "x*y".
friend rational<T> operator /
(const rational<T>&, const rational<T>&): Calcula y retorna la división "x/y".
friend bool operator == (const rational<T>&,
const rational<T>&): compara dos numeros racionales x == y
friend bool operator < (const rational<T>&, const rational<T>&):
compara si un
racional es menor a otro x < y
friend bool operator != (const
rational<T>&, const
rational<T>&):
compara si un
racional es disferente de otro x != y
friend bool operator <= (const
rational<T>&, const
rational<T>&):
compara si un
racional es menor o igual a otro x <= y
friend bool operator >= (const
rational<T>&, const
rational<T>&):
compara si un
racional es mayor o igual a otro x >= y
friend bool operator > (const rational<T>&, const rational<T>&):
compara si un
racional es mayor a otro x > y
friend ostream& operator
<< (ostream &, const
rational<T>& ): Graba el valor
de "r" en el flujo "COUT".
friend istream& operator
>> (istream &, rational<T>& ): Lee del flujo de texto "CIN" el valor de "r".
rational& fromString (const
char* nStr): Establece el varlor de "*this" a partir de la hilera
"nStr".
friend double real (const
rational<T>& ): Conversión a real.
friend INT integer(const rational<T>& ): Conversión a long.
friend bool
check_ok( const rational<T>& r ): Revisa la invariante.
Clase Decimal:
bool operator== (const decimal &x, const
decimal &y) ¿ x == y ?
bool operator< (const decimal &x, const decimal &y)
¿ x < y ?
bool operator> (const decimal &x, const decimal &y)
¿ x > y ?
bool operator!= (const decimal &x, const decimal &y)
¿ x != y ?
bool operator<= (const decimal &x, const decimal &y)
¿ x <= y ?
bool operator>= (const decimal &x, const decimal &y)
¿ x >= y ?
ostream & operator<< (ostream &COUT, const decimal &r) Graba el valor de "r" en el flujo "COUT".
istream & operator>> (istream &CIN, decimal
&r) Lee del flujo de texto "CIN" el valor de "r".
decimal operator+ (const decimal &x, const decimal &y)
"x+y".
decimal operator- (const decimal &x, const decimal &y)
"x-y". -
Calcula y retorna la resta "x-y".
decimal operator * (const decimal &x, const decimal &y)
"x*y".
decimal operator/ (const decimal &x, const decimal &y)
"x/y".
decimal operator% (const decimal &x, const decimal &y)
bool run () : Función principal del la prueba - Requiere que
recién haya sido ejecutado setUp().
virtual void setUp (): Establece el ambiente de prueba.
bool Run
(): Sinónimo de run().
bool runTest
(): Sinónimo de run().
int nPass
() const: Cantidad de pruebas exitosas.
int nError
() const: Cantidad de pruebas que han fallado.
void recordSuccess
(): Registra como exitoso el resultado de una prueba.
virtual void reset (): Anula los
contadores de pruebas.
int countTestCases
() const: Cantidad de pruebas realizadas.
std::string getName
() const: Obtiene el nombre de la prueba.
void setName
(const char *name=0): Le cambia el nombre a la prueba.
const std::string & toString
() const: Hilera "enooorme"
para registrar los mensajes de
pruebas fallidas, separados por "\n".
const std::string & errorString
() const: Sinónimo de toString().
virtual void tearDown
(): Destruye el ambiente de prueba.
El programa
realiza una serie de operaciones con numeros decimales de cualquier tamaño y
asi luego realizar casos de pruebas para corroborar que los operadores matemáticos
para la clase Decimal funcionen correctamente.
-Ningún
objeto puede estar almacenado en la posición nula.
C++, Visual
Studio 2005
Abrir
el proyecto, darle click
en la opción build, ahí seleccionar build test-rational.

test_rational.cpp
![]()
test_rational.obj
C++.lib linker
![]()
test_rational.exe

![]()
![]()
![]()
Este
es un programa de prueba que realiza diversas operaciones con números de tipo decimal. El programa se
ejecuta automáticamente por lo que no es necesario ingresarle ningun dato.

Los datos de prueba que se
utilizaron son números racionales a base de numero decimales.
Pruebas de la suma:
|
Entradas |
Salidas |
|
1/2 + 1/4 |
3/4 |
|
3/4 == 1/4 + 1/2 |
True |
|
1 + 1/4 |
125/100 |
|
125/100 == 1/4 + 1 |
True |
|
1/3 != 33/100 |
True |
|
1/8 + 1/5 |
13/40 |
|
13/40 == 1/5 + 1/8 |
True |
Pruebas de la resta:
|
Entradas |
Salidas |
|
1/2 - 1/4 |
10/40 |
|
-10/40 == 1/4 – 1/2 |
True |
|
1 - 1/4 |
75/100 |
|
-75/100 == 1/4 - 1 |
True |
|
-3/4 == 1/4 - 1 |
True |
|
1/8 - 1/5 |
-3/40 |
|
3/40 == 1/5 – 1/8 |
True |
Pruebas de la multiplicación:
|
Entradas |
Salidas |
|
1/2 * 1/4 |
10/80 |
|
10/80 == 1/4 + 1/2 |
True |
|
1 * 1/4 |
10/40 |
|
10/40 == 1/4 * 1 |
True |
|
1/3 != 33/100 |
True |
|
1/8 * 1/5 |
1/40 |
|
1/40 == 1/5 * 1/8 |
True |
Pruebas de la división:
|
Entradas |
Salidas |
|
(1/2) / (1/4) |
4/2 |
|
(1/2) ==
(1/4) / (1/2) |
True |
|
1 / (1/4) |
4 |
|
(1/4) == (1/4) / 1 |
True |
|
1/3 != 33/100 |
True |
|
(1/8) / (1/5) |
5/8 |
|
(8/5) == (1/5) / (1/8) |
True |
#ifndef ADH_test_h
#define ADH_test_h
///< Evita la inclusión múltiple
#include <string>
// class std::string
#include <sstream>
// class basic_ostringstream<T,Ch>
//#include <limits.h> //
// using namespace std;
/// Definido por la biblioteca C++ estándar.
namespace std {} // Está acá para que Doxygen lo documente
/// Escuela de Ciencias de la Computación e Informática.
/// \see http:www.ecci.ucr.ac.cr
namespace ECCI { }
/// Establece el ambiente en que se realizará cada prueba.
/// - \c TestSuite<TestCase>::run() invoca
los métodos
/// \c TestCase::setUp() y \c
TestCase::tearDown()
/// cuando ejecuta cada prueba.
/// -
/// para facilitar la programación
lo usual es que el
/// programador no incluya
invocaciones a
/// \c TestCase::setUp() y \c
TestCase::tearDown()
/// pues es más simple dejar que
lo haga
/// \c TestSuite<TestCase>::run().
/// - Por eso, si el programador cliente quiere que cada
/// prueba se ejecute luego de
establecer el ambiente con
/// su \c TestFixture, lo más
práctico es que agregue sus
/// pruebas a una colección de
pruebas \c TestSuite.
class
TestFixture {
public:
virtual void setUp() { } ///<
Establece el ambiente de prueba
virtual void tearDown() { } ///<
Destruye el ambiente de prueba
// virtual ~TestCase() {
tearDown(); } ///< Destructor
}; // TestFixture
/// NO IMPLEMENTADO ==> Colector genérico de resultados de prueba.
/// - No está implementado para \c ADH_test.h
/// - En \c ADH_test.h se
/// todos los resultados. \see \c
TestCase::toString().
/// - C++ tiene la ventaja sobre Java porque el programador puede
/// usar las macros \c __FILE__ y
\c __LINE__ para registrar el
/// sitio en que se produce un
error en tiempo de ejecución.
class TestResult
{
private:
TestResult(); ///< Prohibe crear objetos de tipo
\c TestResult.
};
/// NO IMPLEMENTADO ==> Clase abastracta para ejecutar las pruebas y
recolectar los resultados.
/// - No está implementado para \c ADH_test.h
/// - En \c ADH_test.h se
/// todos los resultados. \see \c
TestCase::toString().
class Test {
private: Test(); ///< Prohibe crear objetos de tipo \c Test.
public:
/// Retorna la
cantidad de pruebas a realizar
virtual int countTestCases() = 0;
/// Ejecuta la
prueba y recolecta sus resultados en \c result
virtual void run(TestResult& result) = 0;
};
#include <typeinfo.h>
// class std::type_info ==> char*
typeid().name();
/// Cada caso de prueba es una instancia derivada de esta clase abstracta.
/// - Siempre es obligatorio implementar \c TestCase::run().
class TestCase :
public TestFixture {
protected:
int m_pass;
///< Cantidad de pruebas exitosas
int
m_error; ///< Cantidad de pruebas que han fallado
const char * m_name; ///<
Nombre del caso de prueba
/// Hilera
"enooorme" para registrar los mensajes de pruebas fallidas, separados
por \c "\n"
std::string m_errorString;
public:
TestCase(const
char * name=0);
virtual
~TestCase() { } ///<
Destructor
virtual bool run() = 0; ///<
Ejecuta la prueba y retorna \c "false" si falla
bool
Run() { return
run(); } ///< Sinónimo de \c run()
bool
runTest() { return
run(); } ///< Sinónimo de \c run()
int nPass()
const { return
m_pass; } ///< Cantidad de pruebas exitosas
int
nError() const { return
m_error; } ///< Cantidad de pruebas que han
fallado
void
recordSuccess() { ++m_pass; } ///< Registra
virtual void reset() { m_pass = m_error = 0; m_errorString = ""; } ///<
Anula los contadores de pruebas
public:
int
countTestCases() const { return nPass()+nError(); } ///<
Cantidad de pruebas realizadas
/// Obtiene el
nombre de la prueba
std::string getName() const { return (
m_name != 0 ? m_name : typeid(*this).name()); }
void
setName( const char
* name=0 ) { m_name = name; } ///< Le cambia el
nombre a la prueba
/// Hilera
"enooorme" para registrar los mensajes de pruebas fallidas, separados
por \c "\n"
const
std::string& toString() const { return m_errorString; }
const
std::string& errorString() const { return toString(); } ///<
Sinónimo de \c toString()
protected:
void
recordError( const std::string& lbl, const char* fname, int lineno);
void
testThis( bool cond, const
std::string& lbl, const char* fname, long
lineno);
void
testThis( bool cond, const
char*
lbl, const char*
fname, long lineno) {
testThis( cond, std::string(lbl),
fname, lineno);
} ///< Sinónimo
de \c testThis()
private:
TestCase(const
TestCase&); ///< \c "private" evita la copia de casos de
prueba
TestCase& operator=(const TestCase&); ///<
\c "private" evita la copia de casos de prueba
}; // TestCase
/// NO IMPLEMENTADO ==> Colección de pruebas.
class TestSuite
: public TestCase { };
inline
TestCase::TestCase(const char * name) : m_pass(0), m_error(0), m_name(name),
m_errorString() {
m_errorString = "";
} ///< Constructor
/** Efectúa la prueba y registra el resultado.
- Si la prueba es exitosa sólo
incrementa la cantidad de éxitos \c nPass().
- Si la prueba falla reporta en
\c toString() el hecho.
- La prueba es \c
"cond".
- Los valores \c
"fname" y \c "lineno" indican el archivo y el renglón
en donde se ejecuta la prueba.
- Usualmente los valores de \c
"fname" y \c "lineno" se obtienen con
las macros globales \c
"__FILE__" y \c "__LINE__".
Este método es invocado usando
la macro homónima \c TEST_THIS() */
inline void TestCase::testThis( bool
cond, const std::string& lbl, const char* fname, long lineno) {
if (cond) {
recordSuccess();
}
else {
recordError(lbl, fname, lineno);
}
}
/** Registra la falla de la prueba y luego lo acumula en la hilera de
fallas \c toString().
- Los valores \c
"fname" y \c "lineno" indican el archivo y el renglón
en donde se ejecuta la prueba.
- Usualmente los valores de \c
"fname" y \c "lineno" se obtienen con
las macros globales \c
"__FILE__" y \c "__LINE__".
Este método es invocado usando
la macro \c TEST_ERROR() */
inline void TestCase::recordError( const
std::string& lbl, const char* fname, int
lineno) {
// typedef
basic_ostringstream<char> ostringstream;
std::basic_ostringstream<char> ost; //
ostringstream ost;
ost << "=\\_error:
" << lbl << " \n=/
(" << lineno << ")
" << fname << "\n";
m_errorString += ost.str();
m_error++;
}
/// [ADH_test] Macros propios de \c ADH_test.h
#define
TEST_ADH_test()
#undef TEST_ADH_test
/// [ADH_test] Efectúa la prueba \c cond y registra el resultado.
/// - Si la prueba \c cond tiene éxito invoca el método
/// \c TestCase::recordSuccess()
/// - Si la prueba \c cond falla invoca el método
/// \c TestCase::recordFail()
/// - Esta es una una macro que invoca el método
/// \c TestCase::testThis()
/// \code
/// TEST_THIS("0 != 1");
// Siempre tiene éxito
/// testThis(0 != 1, "0 !=
1", __FILE__, __LINE__ ); // Siempre tiene éxito
/// \endcode
#define
TEST_THIS(cond) testThis( cond, #cond, __FILE__, __LINE__ )
/// [ADH_test] Macro similar a \c TEST_THIS() que
/// - El mensaje \c msg debe ser una hilera literal o un objeto que pueda
/// convertirse en <code>const char *</code>
#define
TEST_THIS_Msg(msg, cond) testThis( cond, msg, __FILE__, __LINE__ )
/// [ADH_test] Registra
/// - El programador cliente es quien determinó que la prueba
/// falló y por eso quiere
registrar ese hecho.
/// - Está implementado comun una macro que invoca
/// el método \c
TestCase::recordError()
///
/// \code
/// if (22==33) {
/// TEST_ERROR("22 !=
33"); // Registra que la prueba falló
/// }
/// \endcode
#define
TEST_ERROR(str) recordError( str, __FILE__, __LINE__ )
/// [ADH_test] Registra
/// - El programador cliente es quien determinó que la prueba
/// fue exitosa y por eso quiere
registrar ese hecho.
/// - Generalmente se
/// se supone debió ser lanzada
/// - Está implementado comun una macro que invoca
/// el método \c
TestCase::recordSuccess()
///
/// \code
/// queue<T> Q(SIZE); // la cola "Q" está vacía ==> no tiene
"front()"
/// try {
/// Q.front(); // Es incorrecto usar un valor de la cola si
la cola está vacía
///
TEST_ERROR("Q.front();"); // Fallaría si "front()"
no levanta la excepción
/// }
/// catch (std::logic_error&)
{
/// TEST_SUCCESS(); // Esto es
lo correcto pues "front()" levanta "logic_error" para unca
cola vacía
/// }
/// \endcode
#define
TEST_SUCCESS() recordSuccess()
/// [ADH_test] Efectúa la prueba para determinar si <code>expected == actual</code>.
/// - Si la prueba tiene éxito invoca el método
/// \c TestCase::recordSuccess()
/// - Si la prueba falla invoca el método
/// \c TestCase::recordFail()
/// - Esta es una una macro que invoca el método
/// \c TestCase::testThis()
#define
TEST_EQUAL(expected, actual) \
testThis( (expected) == (actual),
#expected " == " #actual, __FILE__,
__LINE__ )
/// [ADH_test] Efectúa la prueba para determinar si <code>expected == actual</code>.
/// - Si la prueba tiene éxito invoca el método
/// \c TestCase::recordSuccess()
/// - Si la prueba falla invoca el método
/// \c TestCase::recordFail()
/// - Esta es una una macro que invoca el método
/// \c TestCase::testThis()
/// - Registra el mensaje \c MSG si la prueba falla.
#define
TEST_EQUAL_Msg(MSG, expected, actual) \
testThis( (expected) == (actual), MSG,
__FILE__, __LINE__ )
/// Operación de grabado que permite reportar el resultado de la prueba \c
test.
/// - Graba en \c COUT el nombre, cantidad de éxitos y cantidad de
errores.
std::ostream
& operator << (std::ostream&
COUT, const TestCase& test) {
COUT << "TestCase
\"" <<
test.getName() << "\":\n"
<< "\tOK:
" << test.nPass()
<< "\tERROR:
" << test.nError()
<< "\n";
return
COUT;
}
/// Graba en \c "COUT" el resultado de la prueba \c test.
/// - Retorna la cantidad total de errores \c test.nError().
/// - Además, graba la cantidad de pruebas exitosas y erróneas.
/// - Si hubo pruebas no exitosas, graba los mensajes de error
correspondientes.
inline long Report( std::ostream& COUT, const TestCase &test ) {
COUT << test;
if
(test.nError() != 0) {
COUT << test.errorString();
}
return
test.nError();
}
// ¿¿¿ TestSuite ???
//inline bool check_ok<int>( const int & ) { return true; }
//template<class unsigned> inline bool check_ok( const unsigned
& ) { return true; }
//template<class int> inline bool check_ok( const long & ) { return true; }
//template<class int> inline bool check_ok( const flota & )
{ return true; }
//template<class int> inline bool check_ok( const double &
) { return true; }
template <class T> bool
check_ok( const T& ); ///< Declaración genérica para \c check_ok()
inline bool check_ok( const signed char
& ) { return
true; } ///< \c check_ok<>()
inline bool check_ok( const unsigned char & )
{ return true;
} ///< \c
check_ok<>()
inline bool check_ok( const signed int & ) { return true; } ///< \c check_ok<>()
inline bool check_ok( const unsigned int& ) { return true; } ///< \c check_ok<>()
inline bool check_ok( const signed long
& ) { return
true; } ///< \c check_ok<>()
inline bool check_ok( const unsigned long & )
{ return true;
} ///< \c
check_ok<>()
inline bool check_ok( const float &
) { return
true; } ///< \c check_ok<>()
inline bool check_ok( const double &
) { return
true; } ///< \c check_ok<>()
inline bool check_ok( const long double &
) { return
true; } ///< \c check_ok<>()
/// Retorna una hilera que contiene el valor de \c val.
/// - \c toString() with standard C++
template <class T>
std::string
toString( const T & val ) {
// typedef
basic_ostringstream<char> ostringstream;
std::basic_ostringstream<char> temp; //
ostringstream temp;
temp << val;
return
temp.str( );
}
/// [CppUnit] Macros propios de \c CppUnit
http://cppunit.sourceforge.net/doc/lastest
#define
CPPUNIT_ADH_test()
#undef CPPUNIT_ADH_test
/// [CppUnit] Assertions that a condition is true.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga0
#define
CPPUNIT_ASSERT(condition) TEST_THIS(condition)
/// [CppUnit] Assertion with a user specified message.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga1
#define
CPPUNIT_ASSERT_MESSAGE(message, condition) CPPUNIT_ASSERT(condition)
/// [CppUnit] Fails with the specified message.
/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga2
#define
CPPUNIT_FAIL(message) TEST_ERROR(message)
/// [CppUnit] Asserts that two values are equals.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga3
#define CPPUNIT_ASSERT_EQUAL(expected,
actual) TEST_EQUAL(expected, actual)
/// [CppUnit] Asserts that two values are equals, provides additional
messafe on failure.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga4
#define
CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) \
TEST_EQUAL_Msg(message, expected,
actual)
/// [CppUnit] Macro for primitive value comparisons.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga5
#define
CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) \
assertEquals_Delta(expected, actual,
delta)
/// [CppUnit] Asserts that the given expression throws an exception of the
specified type.
/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga6
#define
CPPUNIT_ASSERT_THROW(expression, ExceptionType)
\
do
{
\
bool
cpputExceptionThrown_ = false; \
try
{ \
expression; \
} catch
( const ExceptionType & ) { \
cpputExceptionThrown_ = true;
\
} \
\
if
( cpputExceptionThrown_ ) {
\
break; \
} \
TEST_ERROR( \
"Expected
exception: " #ExceptionType )
\
} while
( false )
/// [CppUnit] Asserts that the given expression does not throw any
exceptions.
/// \see http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga7
#define
CPPUNIT_ASSERT_NO_THROW(expression) \
do
{
\
try
{
\
expression; \
} catch
( ... ) {
\
TEST_ERROR("Unexpected exception caught"); \
}
\
} while
( false )
/// [CppUnit] Asserts that an assertion fail.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga8
#define
CPPUNIT_ASSERT_ASSERTION_FAIL(assertion) \
CPPUNIT_ASSERT_THROW( assertion,
CPPUNIT_NS::Exception )
/// [CppUnit] Asserts that an assertion pass.
/// \see
http://cppunit.sourceforge.net/doc/lastest/group___assertions.html#ga9
#define
CPPUNIT_ASSERT_ASSERTION_PASS(assertion) \
CPPUNIT_ASSERT_NO_THROW( assertion )
// /// Concatena la hilera \c THIS con la hilera \c THAT
// #define ADH_test_CAT( THIS, THAT ) (std::string(THIS) +
std::string(THAT).c_str()
#define
JUnit_ADH_test()
#undef JUnit_ADH_test
/// [JUnit] Macros propios de \c JUnit
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html
/// Asserts that two objects are
equal.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.Object,%20java.lang.Object)
#define
assertEquals( EXPECTED, ACTUAL )
TEST_EQUAL(EXPECTED, ACTUAL)
/// Asserts that two objects are
equal (with message).
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.String,%20java.lang.Object,%20java.lang.Object)
#define
assertEquals_Msg( MSG, EXPECTED, ACTUAL ) TEST_EQUAL_Msg(MSG, EXPECTED, ACTUAL)
/// [JUnit] Asserts that a condition is true.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertTrue(boolean)
#define
assertTrue( CONDITION )
testThis( CONDITION, #CONDITION, __FILE__, __LINE__ )
/// [JUnit] Asserts that a condition is true (with message).
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertTrue(java.lang.String,%20boolean)
#define
assertTrue_Msg( MSG, CONDITION )
testThis( CONDITION, MSG, __FILE__, __LINE__ )
/// [JUnit] Asserts that a condition is false.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertFalse(boolean)
#define
assertFalse( CONDITION )
testThis( !(CONDITION), "!("
#CONDITION ")", __FILE__, __LINE__
)
/// [JUnit] Asserts that a condition is false (with message).
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertFalse(java.lang.String,%20boolean)
#define
assertFalse_Msg( MSG, CONDITION ) testThis( !(CONDITION), MSG, __FILE__, __LINE__ )
#include <math.h> // fabs()
/// [JUnit] Asserts that two doubles are equal concerning a delta.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(double,%20double,%20double)
#define
assertEquals_Delta(EXPECTED, ACTUAL, DELTA ) \
testThis( fabs( double(EXPECTED) - double(ACTUAL) ) < double(DELTA),
\
"|" #EXPECTED "-"
#ACTUAL "| < " #DELTA, __FILE__, __LINE__ )
/// [JUnit] Asserts that two doubles are equal concerning a delta (with
message).
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertEquals(java.lang.String,%20double,%20double,%20double)
#define
assertEquals_Delta_Msg( MSG, EXPECTED, ACTUAL, DELTA ) \
testThis( fabs( double(EXPECTED) - double(ACTUAL) ) < double(DELTA),
\
MSG, __FILE__, __LINE__ )
/// [JUnit] Asserts that an object is null.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNull(java.lang.Object)
#define
assertNull(OBJECT) testThis( 0==&(OBJECT),
"assertNull(" #OBJECT ")",
__FILE__, __LINE__ )
/// [JUnit] Asserts that an object isn't null.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNotNull(java.lang.Object)
#define
assertNotNull(OBJECT) testThis( 0!=&(OBJECT), "assertNotNull("
#OBJECT ")", __FILE__, __LINE__ )
/// [JUnit] Asserts that two objects refer to the same object.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertSame(java.lang.Object,%20java.lang.Object)
#define
assertSame(THIS, THAT) testThis(
&(THIS)==&(THAT), "assertSame(" #THIS ",
" #THAT ")", __FILE__,
__LINE__ )
/// Asserts that two objects do not
refer to the same object.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#assertNotSame(java.lang.Object,%20java.lang.Object)
#define
assertNotSame(THIS, THAT) testThis( &(THIS)!=&(THAT), "assertNotSame(" #THIS ", " #THAT ")",
__FILE__, __LINE__ )
/// [JUnit] Fails a test with no message.
/// \see http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#fail()
#define fail( )
TEST_ERROR("ERROR")
/// [JUnit] Fails a test with the given message.
/// \see
http://junit.sourceforge.net/javadoc/junit/framework/Assert.html#fail(java.lang.String)
#define fail_Msg(
MSG ) TEST_ERROR(MSG)
#endif //
ADH_test_h
#if !defined(AFX_BIGNUM_H__54FCBDA3_D21D_11D2_9782_444553540000__INCLUDED_)
#define
AFX_BIGNUM_H__54FCBDA3_D21D_11D2_9782_444553540000__INCLUDED_
#if _MSC_VER
> 1000
#pragma once
#endif // _MSC_VER > 1000
#include "LDoble.h"
#include <limits.h>
#include <iostream>
using namespace std;
//typedef PNDoble
const unsigned long int MAXBASE=USHRT_MAX+1;
class
BigNum
{
LDoble *Lis;
char
signo;
private:
virtual void copiar(const
BigNum& a);
public:
//Crea el número
con valor 0.
BigNum();
//Crea el número
con el valor recibido.
BigNum(int);
/*El vector
recibido expresa el número en base 65536. Sign indica
el signo
BigNum(unsigned
short int a[],int cant,char sign);
/*Convierte el
número desde letras */
BigNum(char
*s);
/*Constructor de
copia */
BigNum(const
BigNum& a);
/*Pre : el
número no es mayor que el maximo long (4294967295).
Post: devuelve el número
virtual long A_Numero();
virtual
BigNum& operator = (const BigNum & a);
friend
BigNum operator / (const
BigNum & a, const BigNum & b);
friend
BigNum operator + (const
BigNum & a, const BigNum & b);
friend
BigNum operator - (const
BigNum & a, const BigNum & b);
friend
BigNum operator * (const
BigNum & a, const BigNum & b);
friend
BigNum operator % (const
BigNum & a, const BigNum & b);
friend
ostream& operator << (ostream& s,
const BigNum & m);
virtual int operator == (const BigNum & a) const;
virtual int operator != (const BigNum & a) const;
virtual int operator > (const BigNum & a) const;
virtual int operator < (const BigNum & a) const;
virtual int operator >= (const BigNum & a) const;
virtual int operator <= (const BigNum & a) const;
virtual BigNum&
operator++();
virtual
BigNum& operator--();
virtual
BigNum& operator += (const BigNum & a);
virtual
BigNum& operator -= (const BigNum & a);
virtual
BigNum& operator *= (const BigNum & a);
virtual
BigNum& operator /= (const BigNum & a);
virtual BigNum&
operator %= (const
BigNum & a);
BigNum operator-
() { return BigNum(0)-(*this); }
/* friend BigNum&
operator++(const BigNum& a);
friend BigNum&
operator--(const BigNum& a);*/
virtual
~BigNum();
};
#endif // !defined(AFX_BIGNUM_H__54FCBDA3_D21D_11D2_9782_444553540000__INCLUDED_)
#ifndef decimal_h
#define decimal_h ///< Evita la inclusión múltiple
#include <iostream>
#include "BigNum.h"
#include <cstdlib>
#include <cctype> // isdigit()
class decimal{
private:
BigNum m_num; ///<
Numerador
decimal( const
BigNum& res ) { m_num = res; }
public:
// constructores
decimal() : m_num(0) { } ///< Constructor
de vector
decimal(long
num) : m_num(num) { } ///< Constructor a partir de
un valor entero
decimal(const
decimal& o) /// Constructor de copia
{ m_num = o.m_num; }
~decimal() { } ///<
Destructor
// void num(long n) { m_num=n;
Simplify(); } // FEO
// void den(long d) { m_den= ( d!=0
? d : m_den) ; Simplify(); } // FEO
decimal& operator = (const
decimal&); //
Asignación (copia)
decimal& operator = (long);
decimal& swap ( decimal& );
decimal& operator
+= (const decimal&);
decimal& operator
-= (const decimal&);
decimal& operator
*= (const decimal&);
decimal& operator
/= (const decimal&);
decimal operator - () const; //
menos unario
friend
decimal operator + (const
decimal&, const decimal&);
friend
decimal operator - (const
decimal&, const decimal&);
friend
decimal operator * (const
decimal&, const decimal&);
friend
decimal operator / (const
decimal&, const decimal&);
friend
decimal operator % (const
decimal&, const decimal&);
friend bool operator == (const decimal&, const
decimal&);
friend bool operator
< (const
decimal&, const decimal&);
friend bool operator != (const decimal&, const
decimal&);
friend bool operator <= (const decimal&, const
decimal&);
friend bool operator >= (const decimal&, const
decimal&);
friend bool operator
> (const
decimal&, const decimal&);
friend
ostream& operator << (ostream &, const decimal& );
friend
istream& operator >> (istream
&, decimal& );
}; // rational
/** 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
decimal& decimal::operator = (const decimal& o) {
m_num = o.m_num;
// 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
decimal& decimal::swap ( decimal& o ) {
#if 1
decimal tmp = o;
o = *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
decimal& decimal::operator = (long entero) {
m_num = entero;
return *this;
} // operator =
/// Multiplica \c "*this" por \c "num".
inline
decimal& decimal::operator *= (const decimal& num) {
BigNum m_res;
m_res = m_num * num.m_num;
m_num = m_res;
return *this;
} // operator *=
/** Divide \c "*this" por
el valor de \c "num".
\pre
- (num != 0)
*/
inline
decimal& decimal::operator /= (const decimal& num) {//lo
cambiamos
BigNum m_res;
m_res = m_num / num.m_num;
m_num = m_res;
return *this;
} // operator /=
/// \c "-x".
/// - Menos unario
/// - Calcula y retorna el valor \c "-x"
inline decimal
decimal::operator - () const
{
decimal tmp = (*this); // tmp.rational(
*this );
tmp.m_num = - tmp.m_num;
return tmp;
} // operator -
/// ¿ x == y ?
inline bool operator == (const decimal &x, const
decimal &y) {
return
(x.m_num == y.m_num);
} // operator ==
/// ¿ x < y ?
inline bool operator < (const decimal &x, const
decimal &y) {
return
x.m_num < y.m_num;
} // operator <
/// ¿ x > y ?
inline bool operator > (const decimal &x, const
decimal &y) {
return (y
< x);
} // operator >
/// ¿ x != y ?
inline bool operator != (const decimal& x, const
decimal& y) {
return !(x
== y);
} // operator !=
/// ¿ x <= y ?
inline bool operator <= (const decimal& x, const
decimal& y) {
return !(y
< x);
} // operator <=
/// ¿ x >= y ?
inline bool operator >= (const decimal& x, const
decimal& y) {
return !(x
< y);
} // operator >=
// EOF: rational.h
/// Le suma a \c "*this" el valor de \c "otro".
decimal&
decimal::operator += (const
decimal& otro) {
BigNum m_res;
m_res = m_num + otro.m_num;
m_num = m_res;
return *this;
} // operator +=
/// Le resta a \c "*this" el valor de \c "otro".
decimal&
decimal::operator -= (const
decimal& otro) {
BigNum m_res;
m_res = m_num - otro.m_num;
m_num = m_res;
return *this;
} // operator -=
/** Graba el valor de \c "r" en el flujo \c "COUT".
- Graba el valor en el formato
[num/den].
- En particular, este es el
operador que se invoca
cuando se
\code
cout << r <<
q;
\endcode
*/
ostream&
operator<< (ostream &COUT, const decimal& r) {
return
COUT << "[" << r.m_num
<< "]" ;
} // operator
<<
/** Lee del flujo de texto \c "CIN" el valor de \c
"r".
\pre
El número rational debe haber
sido escrito usando
el formato "[r/den]",
aunque es permisible usar
algunos blancos.
- Se termina de leer el valor
sólo cuando encuentra \c "]".
- <code> [ -+-+-+-+- 4 /
-- -+ -- 32 ] </code> se lee
<code> [1/8]
</code>
*/
istream&
operator >> (istream &CIN,
decimal& r) {
/*char ch; // valor leido, letra por letra, de
"CIN"
bool es_positivo = true; // manejo de los signos + y -
// se brinca todo hasta el
primer dígito
do {
CIN >> ch;
if (ch == '-') { // cambia de signo
es_positivo =
!es_positivo;
}
} while (!isdigit(ch));
// se traga el numerador
r.m_num = 0;
while (isdigit(ch)) { //
convierte a decimal: izq --> der
r.m_num = 10 * r.m_num +
(ch-'0');
CIN >> ch;
}
// se brinca los blancos después
while (isspace(ch)) {
CIN >> ch;
}
if (ch ==']') { // es un número
entero
r.m_den = 1;
}
else {
do { // se brinca todo hasta el denominador
CIN >> ch;
if (ch == '-') {
es_positivo =
!es_positivo;
}
} while (!isdigit(ch));
// se traga el denominador
r.m_den = 0;
while (isdigit(ch)) {
r.m_den = 10 * r.m_den +
(ch-'0');
CIN >> ch;
}
// El programa se duerme si
en el flujo de entrada
// NO aparece el caracter
delimitador final "]",
// pues la lectura termina
hasta encontrar el "]".
while (ch != ']') {
CIN >> ch;
}
} // corrección: Andrés Arias
<[email protected]>
// le cambia el signo, si hace
falta
if (! es_positivo) {
r.m_num = -r.m_num;
}
return CIN;
*/
return
CIN;
} // operator
>>
/// \c "x+y".
/// - Calcula y retorna la suma \c "x+y".
decimal operator + (const
decimal &x, const decimal &y) {
return
decimal(x.m_num + y.m_num);
} // operator + ()
/// \c "x-y".
/// - Calcula y retorna la resta \c "x-y".
decimal operator - (const
decimal &x, const decimal &y) {
return
decimal(x.m_num - y.m_num);
} // operator - ()
/// \c "x*y".
/// - Calcula y retorna la multiplicación \c "x*y".
decimal operator * (const
decimal &x, const decimal &y) {
return
decimal(x.m_num * y.m_num);
} // operator * ()
/// \c "x/y".
/// - Calcula y retorna la división \c "x/y".
/// \pre <code> y != 0 </code>
decimal operator / (const
decimal &x, const decimal &y) {
return
decimal(x.m_num / y.m_num);
} // operator / ()
decimal operator % (const
decimal &x, const decimal &y) {
return
decimal(x.m_num % y.m_num);
} // operator / ()
#endif // rational_h
#ifndef LDoble_h
#define LDoble_h
typedef unsigned short int TDato;
typedef unsigned long int TMayor;
/// Nodo de la lista.
class NDoble {
public:
TDato Dato; ///<
Valor almacenado.
NDoble *Sig,*Ant; ///<
Punteros de la lista doblemente enlazada.
public:
NDoble(TDato dato=0) : Dato(Dato), Sig(0),
Ant(0) { }
virtual
~NDoble() { }
};
#define TRUE 1
#define FALSE 0
typedef int Boolean;
typedef NDoble*
PNDoble;
/// Lista doblemente enlazada.
class LDoble {
PNDoble Prim,Ult; /*,*Cte*/
int
CantNodos;
public:
int
CantRefs;
LDoble();
//Post: devuelve
TRUE si no tiene elementos, sino FALSE.
virtual
Boolean Vacia();
//Post: Elimina
todos los elementos de la lista y libera la memoria.
virtual void Vaciar();
/*Post: inserta
el elemento dat en la posición anterior al corriente.
si la lista estaba vacía lo inserta en
el primer lugar. dat
es el nuevo corriente. */
virtual int InsAntes(PNDoble& Cte, TDato dat);
/*Post: inserta
el elemento dat en la posición posterior al corriente.
si la lista estaba vacía lo inserta en
el primer lugar. dat
es el nuevo corriente. */
virtual int InsDespues(PNDoble& Cte, TDato dat);
/* direccion
indica adonde se mueve el corriente. Valores posibles:
'p' (primer elemento), 's' (elemento
siguiente), 'a' (elem. anterior),
'u' (último elemento). */
virtual int MoverCte(PNDoble& Cte, char direccion);
/*Pre : La lista
no está vacía.
Post: Devuelve el valor del Corriente. */
virtual
TDato ObtCte(PNDoble Cte);
/*Pre : La lista
no está vacía.
Post: Modifica el valor
Si existe el
corriente devuelve 0.
*/
virtual int ModifCte(PNDoble& Cte, TDato dat);
/*Pre : La lista
no está vacía.
Post: Elimina el elemento actual (Corriente).
El corriente es el
siguiente. Si era el
último es el anterior. */
virtual int ElimCte(PNDoble& Cte);
/*Post: Devuelve
la cantidad de elementos guardados en la lista.
*/
virtual int CantElem();
/* Destructor:
libera todo el espacio ocupado por la lista */
virtual
~LDoble();
};
#endif
#ifndef rational_h
#define rational_h
///< Evita la inclusión múltiple
#include <iostream>
using namespace std;
/** La clase \c rational implementa
las operaciones aritméticas
principales para números
rationales.
- <code> [1/3] == [2/6]
== ...
[9/27] == ... </code>
- <code> [1/3] * [2/6] / [3/9] - [9/27] </code>
*/
template <class INT>
class rational {
private:
INT m_num; ///<
Numerador
INT m_den; ///<
Denominador
void
Simplify();
public:
// constructores
rational() : m_num(0), m_den(1) { } ///< Constructor
de vector
rational(INT num) : m_num(num), m_den(1) { } ///< Constructor a partir de un valor entero
rational(INT num, INT den)
: m_num(num), m_den(den) { Simplify();
} ///< Constructor a partir de un valor quedbrado
rational(const
rational& o) /// Constructor de
copia
{ m_num = o.m_num, m_den = o.m_den; }
~rational() { } ///<
Destructor
void
set(INT num=0, INT den=1); // Le cambia el valor a \c "*this"
INT num() const
{ return m_num; } ///< Copia del
numerador
INT 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 = (INT);
rational& swap ( rational& );
rational& operator
+= (const rational&);
rational& operator
-= (const rational&);
rational& operator
*= (const rational&);
rational& operator
/= (const rational&);
rational operator - () const; //
menos unario
template
<class T> friend
rational<T> operator + (const rational<T>&, const rational<T>&);
template
<class T> friend
rational<T> operator - (const rational<T>&, const rational<T>&);
template
<class T> friend
rational<T> operator * (const rational<T>&, const rational<T>&);
template
<class T> friend
rational<T> operator / (const rational<T>&, const rational<T>&);
template
<class T> friend
bool operator
== (const rational<T>&, const rational<T>&);
template
<class T> friend
bool operator
< (const
rational<T>&, const
rational<T>&);
template
<class T> friend
bool operator
!= (const rational<T>&, const rational<T>&);
template
<class T> friend
bool operator
<= (const rational<T>&, const rational<T>&);
template
<class T> friend
bool operator
>= (const rational<T>&, const rational<T>&);
template
<class T> friend
bool operator
> (const
rational<T>&, const
rational<T>&);
template
<class T> friend
ostream& operator << (ostream &, const rational<T>& );
template
<class T> friend
istream& operator >> (istream
&, rational<T>& );
rational& fromString (const char* nStr);
template
<class T> friend
double real
(const rational<T>& ); // Conversión a
real
template
<class T> friend
INT integer(const
rational<T>& ); // Conversión a long
template
<class T> friend
bool check_ok( const
rational<T>& r ); // Ok()
}; // rational
template <class INT>
INT mcd(INT
x, INT y); // Calcula el Máximo Común Divisor
/// Sinónimo de \c mcd(x,y) <code> [ inline ] </code>
template <class INT>
inline INT
gcd(INT x, INT y) { return mcd(x,y); }
/// Cambia el valor
template <class INT>
inline void rational<INT>::set(INT n, INT 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
*/
template <class INT>
inline
rational<INT>& rational<INT>::operator
= (const rational<INT>& 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
*/
template <class INT>
inline
rational<INT>& rational<INT>::swap ( rational<INT>& o
) {
#if 1
rational tmp = o;
o = *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".
template <class INT>
inline
rational<INT>& rational<INT>::operator
= (INT entero) {
m_num = entero;
m_den = 1;
return *this;
} // operator =
/// Multiplica \c "*this" por \c "num".
template <class INT>
inline
rational<INT>& rational<INT>::operator
*= (const rational<INT>& num) {
m_num *= num.m_num;
m_den *= num.m_den;
Simplify();
return *this;
} // operator *=
/** Divide \c "*this" por
el valor de \c "num".
\pre
- (num != 0)
*/
template <class INT>
inline
rational<INT>& rational<INT>::operator
/= (const rational<INT>& 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"
template <class INT>
inline
rational<INT> rational<INT>::operator
- () const {
rational tmp = (*this); // tmp.rational(
*this );
tmp.m_num = - tmp.m_num;
return tmp;
} // operator -
/// ¿ x == y ?
template <class INT>
inline bool operator == (const rational<INT> &x, const rational<INT> &y) {
return
(x.m_num == y.m_num) && (x.m_den == y.m_den);
/* Nota:
ocurrir que [1/1] está
almacenado
basta comparar los valores campo
por campo para determinar si se
da o no la igualdad.
*/
} // operator ==
/// ¿ x < y ?
template <class INT>
inline bool operator < (const rational<INT> &x, const rational<INT> &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 ?
template <class INT>
inline bool operator > (const rational<INT> &x, const rational<INT> &y) {
return (y
< x);
} // operator >
/// ¿ x != y ?
template <class INT>
inline bool operator != (const rational<INT>& x, const rational<INT>& y) {
return !(x
== y);
} // operator !=
/// ¿ x <= y ?
template <class INT>
inline bool operator <= (const rational<INT>& x, const rational<INT>& y) {
return !(y
< x);
} // operator <=
/// ¿ x >= y ?
template <class INT>
inline bool operator >= (const rational<INT>& x, const rational<INT>& y) {
return !(x
< y);
} // operator >=
/// Convertidor a punto flotante.
template <class INT>
inline double real(const
rational<INT>& num) {
return double (num.m_num) / double
(num.m_den);
} // real()
/// Convertidor a punto fijo.
template <class INT>
inline INT
integer(const rational<INT>& num) {
return
INT (num.m_num / num.m_den);
} // integer()
#if 0
/// Convertidor a punto fijo
inline rational::operator INT() {
return INT (m_num / m_den);
} //
rational::operator long
#endif
template <class INT>
bool
check_ok_externo( const
rational<INT>& r );
#include <cstdlib>
#include <cctype> // isdigit()
/** Verifica la invariante de la clase \c rational.
\par <em>Rep</em>
Modelo de la clase:
\code
+---+
| 3 | <== m_num == numerador
+---+
|134| <== m_den == denominador
+---+
\endcode
- http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep
\remark
Libera al programador de
implementar el método \c Ok()
-
http://www.di-mare.com/adolfo/binder/c04.htm#sc11
*/
template <class INT>
bool check_ok( const rational<INT>& r ) {
if (&r
== 0) {
/// -
Invariante: ningún objeto puede estar almacenado en la posición nula.
return false;
}
if ( !
(r.m_den > 0) ) {
/// -
Invariante: el denominador debe ser un número positivo.
return false;
}
if (r.m_num == 0) {
if (
r.m_den == 1 ) {
/// -
Invariante: el cero debe representarse con denominador igual a "1".
return
true;
}
else {
return
false;
}
}
if ( ! (
mcd(r.m_num, r.m_den) == 1 ) ) {
/// -
Invariante: el numerador y el denominador deben ser primos relativos.
return false;
}
return true;
} // check_ok()
/** Verifica la invariante de la clase \c rational.
\remark
Esta implementación nos se le
mete al <em>Rep</em>
(casi siempre no es posible
implementar una función
-
http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep
\remark
Libera al programador de
implementar el método \c Ok()
- http://www.di-mare.com/adolfo/binder/c04.htm#sc11
*/
template <class INT>
bool
check_ok_no_Rep( const rational<INT>&
r ) {
if (&r
== 0) {
/// -
Invariante: ningún objeto puede estar almacenado en la posición nula.
return false;
}
if ( !
(r.den() > 0) ) {
/// -
Invariante: el denominador debe ser un número positivo.
return false;
}
if (r.num()
== 0) {
if (
r.den() == 1 ) {
/// -
Invariante: el cero debe representarse con denominador igual a "1".
return true;
}
else {
return
false;
}
}
if ( ! (
mcd(r.num(), r.den()) == 1 ) ) {
/// -
Invariante: el numerador y el denominador deben ser primos relativos.
return false;
}
return true;
} // check_ok_no_Rep()
/** Calcula el Máximo Común Divisor de los números \c "x" y \c
"y".
- <code> mcd(x,y) >= 1
</code> siempre.
- MCD <==> GCD: <em>
Greatest Common Divisor </em>.
\pre
<code> (y != 0)
</code>
\remark
Se
\par Ejemplo:
\code
2*3*5 == mcd( 2*2*2*2 * 3*3 *
5*5, 2*3*5 )
30 == mcd( -3600, -30 )
\endcode
*/
template <class INT>
INT mcd(INT
x, INT y) {
INT g = (x < 0 ? -x : x); // trabaja con valores positivos
INT r = (y < 0 ? -y : y); // "r" es el resto
INT temp;
do {
temp = r;
r
= g % r;
g
= temp;
} while (0
!= r);
return g;
} // mcd()
/** Simplifica el numerador y el denomidador.
- Transforma el número rational de manera que el numerador y el
denominador sean primos
relativos, asegurando además que el
denominador es siempre
positivo.
- Si <code>(m_num==0)
==> (m_den==1)</code>.
- Simplifica la fracción para que
\c m_num y \c m_den sean números
primos relativos ie,
<code>mcd(m_num,m_den) == 1</code>.
- Asegura que \c m_den sea un
número positivo.
- Restaura la invariante de la
clase \c rational.
*/
template <class INT>
void
rational<INT>::Simplify() {
if (m_num
== 0) {
m_den = 1;
}
INT divisor = mcd(m_num, m_den);
if (divisor
> 1) { //
==> (divisor != 0)
m_num /= divisor;
m_den /= divisor;
}
if (m_den
< 0) {
m_num = -m_num;
m_den = -m_den;
}
} //
rational::Simplify()
/// Le suma a \c "*this" el valor de \c "otro".
template <class INT>
rational<INT>&
rational<INT>::operator += (const rational<INT>& otro) {
m_num
= m_num * otro.m_den + m_den * otro.m_num;
m_den *= otro.m_den;
Simplify();
return *this;
} // operator +=
/// Le resta a \c "*this" el valor de \c "otro".
template <class INT>
rational<INT>&
rational<INT>::operator -= (const rational<INT>& otro) {
INT oldm_den = m_den;
INT oldm_num = m_num;
INT
d = otro.m_den;
INT n
= otro.m_num;
m_den *= d;
m_num = oldm_num * d - oldm_den * n;
Simplify();
return *this;
} // operator -=
/// Establece el varlor de \c "*this" a partir de la hilera \c
"nStr".
/// \pre \c "nStr" debe estar escrita en el formato
"[num/den]".
template <class INT>
rational<INT>&
rational<INT>::fromString (const char* nStr) {
char
ch; // valor
obtenido, caracter por caracter, de "nStr"
bool
es_positivo = true; // manejo de los
signos + y -
// se brinca todo
hasta el primer dígito
do {
ch = *nStr; nStr++;
if (ch
== '-') {
// cambia de signo
es_positivo = !es_positivo;
}
} while
(!isdigit(ch));
// se traga el
numerador
INT num = 0;
while
(isdigit(ch)) { // convierte a decimal: izq -->
der
num = 10 * num + (ch-'0');
ch = *nStr; nStr++;
}
// se brinca los
blancos después
while
(isspace(ch)) {
ch = *nStr; nStr++;
}
INT den;
if (ch ==']') { // es un número
entero
den = 1;
}
else {
do
{ // se brinca
todo hasta el denominador
ch = *nStr; nStr++;
if
(ch == '-') {
es_positivo = !es_positivo;
}
}
while (!isdigit(ch));
// se traga
el denominador
den = 0;
while
(isdigit(ch)) {
den = 10 * den + (ch-'0');
ch = *nStr; nStr++;
}
// Ya no
importa si aparece o no el ']'
}
// le cambia el
signo, si hace falta
if (!
es_positivo) {
num = -num;
}
set( num, den );
return *this;
}
/** Graba el valor de \c "r" en el flujo \c "COUT".
- Graba el valor en el formato
[num/den].
- En particular, este es el
operador que se invoca
cuando se
\code
cout << r <<
q;
\endcode
*/
template <class INT>
ostream&
operator<< (ostream &COUT, const rational<INT>& r) {
if ( r.m_den
== 1 ) { // no hay parte fraccional
return
COUT << "[" << r.m_num
<< "]" ;
} else {
return
COUT << "[" << r.m_num
<< "/" << r.m_den
<< "]" ;
}
} // operator
<<
/** Lee del flujo de texto \c "CIN" el valor de \c
"r".
\pre
El número rational debe haber sido escrito
usando
el formato "[r/den]",
aunque es permisible usar
algunos blancos.
- Se termina de leer el valor
sólo cuando encuentra \c "]".
- <code> [ -+-+-+-+- 4 /
-- -+ -- 32 ] </code> se lee
<code> [1/8] </code>
*/
template <class INT>
istream&
operator >> (istream &CIN,
rational<INT>& r) {
char
ch; // valor
leido, letra por letra, de "CIN"
bool
es_positivo = true; // manejo de los
signos + y -
// se brinca todo
hasta el primer dígito
do {
CIN >> ch;
if (ch
== '-') {
// cambia de signo
es_positivo = !es_positivo;
}
} while
(!isdigit(ch));
// se traga el
numerador
r.m_num = 0;
while
(isdigit(ch)) { // convierte a decimal: izq -->
der
r.m_num = 10 * r.m_num + (ch-'0');
CIN >> ch;
}
// se brinca los
blancos después
while
(isspace(ch)) {
CIN >> ch;
}
if (ch ==']') { // es un número
entero
r.m_den = 1;
}
else {
do
{ // se brinca
todo hasta el denominador
CIN >> ch;
if
(ch == '-') {
es_positivo = !es_positivo;
}
} while
(!isdigit(ch));
// se traga
el denominador
r.m_den = 0;
while
(isdigit(ch)) {
r.m_den = 10 * r.m_den + (ch-'0');
CIN >> ch;
}
// El
programa se duerme si en el flujo de entrada
// NO aparece
el caracter delimitador final "]",
// pues la lectura
termina hasta encontrar el "]".
while
(ch != ']') {
CIN >> ch;
}
} // corrección: Andrés Arias
<[email protected]>
// le cambia el
signo, si hace falta
if (!
es_positivo) {
r.m_num = -r.m_num;
}
r.Simplify();
return CIN;
/*
no detecta errores...
[1/0] lo lee y no se queja
[ !#!#!$#@! 3/ aaaa 4 jajaja ] lo lee
... pero no se supone que el
usuario cometa errores...
*/
} // operator
>>
/// \c "x+y".
/// - Calcula y retorna la suma \c "x+y".
template <class INT>
rational<INT>
operator + (const
rational<INT> &x, const
rational<INT> &y) {
INT res_num, res_den;
res_den = x.m_den * y.m_den;
res_num = x.m_num * y.m_den + x.m_den *
y.m_num;
return rational<INT>(res_num, res_den);
} // operator + ()
/// \c "x-y".
/// - Calcula y retorna la resta \c "x-y".
template <class INT>
rational<INT>
operator - (const
rational<INT> &x, const
rational<INT> &y) {
INT res_num, res_den;
res_den = x.m_den * y.m_den;
res_num = x.m_num * y.m_den - x.m_den *
y.m_num;
return
rational<INT>(res_num, res_den);
} // operator - ()
/// \c "x*y".
/// - Calcula y retorna la multiplicación \c "x*y".
template <class INT>
rational<INT>
operator * (const
rational<INT> &x, const
rational<INT> &y) {
INT res_num, res_den;
res_num = x.m_num * y.m_num;
res_den = x.m_den * y.m_den;
return
rational<INT>(res_num, res_den);
} // operator * ()
/// \c "x/y".
/// - Calcula y retorna la división \c "x/y".
/// \pre <code> y != 0 </code>
template <class INT>
rational<INT>
operator / (const
rational<INT> &x, const
rational<INT> &y) {
INT res_num, res_den;
if (0 !=
y.m_num) {
res_num = x.m_num * y.m_den;
res_den = x.m_den * y.m_num;
}
return
rational<INT>(res_num, res_den);
} // operator / ()
#endif //
rational_h
#include "BigNum.h"
#include <Math.h>
#include <String.h>
#include <stdlib.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
long
BigNum::A_Numero()
{
PNDoble Cte=0;
int
i,err=0;
TMayor aux=0;
for
(i=0,err=Lis->MoverCte(Cte,'p');(err==0);i++,err=Lis->MoverCte(Cte,'s'))
aux+=TMayor(Lis->ObtCte(Cte)*pow(double(MAXBASE),i)); /*Este
casteo es para
que no me ponga warnings
por posible pérdida (double-->unsigned int) */
return(signo*aux);
}
/*
BigNum::BigNum(unsigned short int a[],int cant)
{
int i;
signo=1;
for (i=0;i<cant;i++)
Lis->InsDespues(a[i]);
}
*/
BigNum::BigNum(int Nro)
{
int
num=Nro;
Lis = new
LDoble;
if
(num<0) {
signo=-1;
num=abs(num); }
else
signo=1;
TDato n;
PNDoble Cte=0;
// Lis->MoverCte(Cte, 'p');
if
(num!=0)
/*Lis->InsDespues(0);*/
{
do {
n=num % MAXBASE;
num=num / MAXBASE;
Lis->InsDespues(Cte,n); }
while
(num);
}
}
BigNum::BigNum(unsigned short int a[],int cant,char sign) {
int i;
Lis = new
LDoble;
PNDoble Cte=0;
for
(i=0;i<cant;i++)
Lis->InsDespues(Cte,a[i]);
signo=sign;
}
BigNum::BigNum()
{
Lis = new
LDoble;
signo=1;
}
BigNum::BigNum(char *s)
{
char *p;
int i;
int neg=0;
unsigned long int sum;
Lis = new
LDoble;
p=s;
if (*p=='-') {
neg=1;
p++;}
signo=1;
do {
for(i=0,sum=0;((*p)
&& (i<9));i++,p++)
sum=sum*10+(*p-'0');
(*this)*=pow(double(10),i);
(*this)+=sum;
}
while
(*p);
if (neg)
signo=-1;
}
ostream& operator
<< (ostream& s, const BigNum & m) {
char
cad[1000000];
char
cadaux[11];
char*
pcad;
int
lenaux;
int neg=0;
int i;
BigNum aux(m);
BigNum billon=1000000000,resto;
// s<<endl<<"Hasta
aqui todo bien[BigNum & billon=1000000000,resto;]"<<endl;
cin.get();
if
(aux.signo==-1) {
neg=1;
aux.signo=1;
}
cad[999999]='\0';
pcad=cad + 999998;
*pcad = 0;
s<<endl<<"Hasta aqui todo bien[while]"<<endl;
cin.get();
while
(aux!=0) {
resto=aux % billon;
aux/=billon;
_ltoa(resto.A_Numero(),cadaux,10);
lenaux = strlen(cadaux);
for
(i=1; i<=lenaux; i++) {
pcad--;
*pcad = cadaux[lenaux-i];
}
for
(; i<=9; i++) {
pcad--;
*pcad = '0';
}
/* strncpy(cero, ceros,
9-strlen(cadaux));
strcpy(cad, strcat(cero,
cad));
strcpy(cad,strcat(cadaux,cad));*/
}
// s<<endl<<"Hasta
aqui todo bien[fin de while]"<<endl;
cin.get();
pcad += 9-lenaux;
if
(!cad[0]) {
cad[0]='\0';
cad[1]='\0';
}
// s<<endl<<"Hasta
aqui todo bien[cad]"<<endl;
cin.get();
if(neg) s
<<'-'<< pcad;
else s
<< pcad;
// s<<endl<<"Hasta
aqui todo bien[return]"<<endl;
cin.get();
return(s);
}
BigNum::BigNum(const BigNum& a)
{
// copiar(a);
Lis=a.Lis;
Lis->CantRefs++;
signo=a.signo;
}
BigNum::~BigNum()
{
// Lis->Vaciar();
if
(Lis->CantRefs==1)
delete
Lis;
else
Lis->CantRefs--;
}
void
BigNum::copiar(const BigNum& a)
{
int err;
PNDoble Cte=0, CteA=0;
signo=a.signo;
for
(err=a.Lis->MoverCte(CteA, 'p');(!err);err=a.Lis->MoverCte(CteA,
's'))
Lis->InsDespues(Cte,a.Lis->ObtCte(CteA));
}
/* OPERADORES DE COMPARACIÓN */
int BigNum::operator ==(const
BigNum & a) const
{
PNDoble Cte=0, CteA=0;
int
err=Lis->MoverCte(Cte,'p'),err_a=a.Lis->MoverCte(CteA,'p');
TDato cif,cif_a;
if
((Lis->CantElem()==a.Lis->CantElem()) && (signo==a.signo)) {
while
(!err) {
cif=Lis->ObtCte(Cte);
cif_a=a.Lis->ObtCte(CteA);
if
(cif!=cif_a)
return(0);
err=Lis->MoverCte(Cte,'s');
a.Lis->MoverCte(CteA,'s');}
return(1);}
else
return(0);
}
int BigNum::operator !=(const
BigNum & a) const
{
return(!(*this==a));
}
int BigNum::operator >(const
BigNum & a) const
{
PNDoble Cte=0, CteA=0;
if
(signo!=a.signo)
return((signo>a.signo));
if
(Lis->CantElem()==a.Lis->CantElem()) {
int
err=Lis->MoverCte(Cte,'u'),err_a=a.Lis->MoverCte(CteA,'u');
TDato cif,cif_a;
while
(!err) {
cif=Lis->ObtCte(Cte);
cif_a=a.Lis->ObtCte(CteA);
if
(cif!=cif_a)
return((cif>cif_a));
err=Lis->MoverCte(Cte,'a');
a.Lis->MoverCte(CteA,'a');}
return(0);}
else
return((Lis->CantElem()>a.Lis->CantElem()));
}
int BigNum::operator <(const
BigNum & a) const
{
PNDoble Cte=0, CteA=0;
if
(signo!=a.signo)
return((signo<a.signo));
if
(Lis->CantElem()==a.Lis->CantElem()) {
int
err=Lis->MoverCte(Cte,'u'),err_a=a.Lis->MoverCte(CteA,'u');
TDato cif,cif_a;
while
(!err) {
cif=Lis->ObtCte(Cte);
cif_a=a.Lis->ObtCte(CteA);
if
(cif!=cif_a)
return((cif<cif_a));
err=Lis->MoverCte(Cte,'a');
a.Lis->MoverCte(CteA,'a');}
return(0);}
else
return((Lis->CantElem()<a.Lis->CantElem()));
}
int BigNum::operator >=(const
BigNum & a) const
{
return(!(*this<a));
}
int BigNum::operator <=(const
BigNum & a) const
{
return(!(*this>a));
}
BigNum&
BigNum::operator = (const
BigNum & a)
{
/* if (&a==this)
return(*this);
else
{ */
/*BigNum
aux;
aux.copiar(a);*/
Lis->Vaciar();
copiar(a);
return(*this);
}
BigNum operator + (const
BigNum & a, const BigNum & b)
{
BigNum r;
PNDoble CteA, CteB, Cte=0;
/*if
(&a==&b) {
BigNum dos =2;
r=a*dos;
return(r);} */
if
(a.signo!=b.signo) {
if
(a.signo==-1) {
const_cast<BigNum&>(a).signo=1;
r=b-a;
const_cast<BigNum&>(a).signo=-1;}
else
{
const_cast<BigNum&>(b).signo=1;
r=a-b;
const_cast<BigNum&>(b).signo=-1;}
return(r);
}
else {
int
err_a=a.Lis->MoverCte(CteA,'p'),err_b=b.Lis->MoverCte(CteB,'p');
TDato cif_a,cif_b;
TDato pongo,mellevo=0;
TMayor aux;
while
(!(err_a && err_b)) {
if
(err_a)
cif_a=0;
else
cif_a=a.Lis->ObtCte(CteA);
if
(err_b)
cif_b=0;
else
cif_b=b.Lis->ObtCte(CteB);
aux=cif_a+cif_b+mellevo;
pongo=aux % MAXBASE;
mellevo=aux / MAXBASE;
r.Lis->InsDespues(Cte,pongo);
err_a=a.Lis->MoverCte(CteA,'s');
err_b=b.Lis->MoverCte(CteB,'s');
}
if
(mellevo)
r.Lis->InsDespues(Cte,mellevo);
r.signo=a.signo;
return(r);
}
}
BigNum operator - (const
BigNum & a, const BigNum & b)
{
PNDoble CteA, CteB, Cte=0;
BigNum r;
/* if (&a==&b) {
return(0);} */
if
(a.signo!=b.signo) {
if
(b.signo==-1) {
const_cast<BigNum&>(b).signo=1;
r=a+b;
const_cast<BigNum&>(b).signo=-1;}
else
{
const_cast<BigNum&>(b).signo=-1;
r=a+b;
const_cast<BigNum&>(b).signo=1;}
return(r);}
else
if
(a.signo==-1){
const_cast<BigNum&>(a).signo=1;
const_cast<BigNum&>(b).signo=1;
r=b-a;
const_cast<BigNum&>(a).signo=-1;
const_cast<BigNum&>(b).signo=-1;
return(r);}
//Si llega a
este punto los dos son positivos
if
(a<b) {
r=b-a;
r.signo*=-1;
return(r);}
int
err_a=a.Lis->MoverCte(CteA,'p'),err_b=b.Lis->MoverCte(CteB,'p');
TDato cif_a,cif_b;
TDato pongo,mellevo=0;
int
cont=0,i;
signed long aux;
while
(!(err_a)) {
cif_a=a.Lis->ObtCte(CteA);
if
(err_b)
cif_b=0;
else
cif_b=b.Lis->ObtCte(CteB);
aux=cif_a-cif_b-mellevo;
if
(aux<0) {
pongo=aux+MAXBASE;
mellevo=1;}
else
{
pongo=aux;
mellevo=0;}
if
(pongo==0)
cont++;
else
{
for(i=1;i<=cont;i++)
r.Lis->InsDespues(Cte,0);
cont=0;
r.Lis->InsDespues(Cte,pongo);}
err_a=a.Lis->MoverCte(CteA,'s');
err_b=b.Lis->MoverCte(CteB,'s');}
return(r);
}
/*BigNum operator * (const class BigNum & a,const class BigNum &
b) {
BigNum & aaux;
BigNum & baux;
aaux=a;
baux=b;
return(aaux*baux);
}*/
BigNum operator * (const
BigNum & a, const BigNum & b)
{
BigNum r;
/* if (&a==&b) {
BigNum & baux=b;
return(a*baux);}*/
PNDoble CteA, CteB, Cte=0;
r.signo=a.signo*b.signo;
int
err_b,err_a,err=1;
int
i,comienzo=0;
TMayor aux;
TDato mellevo=0,mellevo2=0;
TMayor cif;
for
(err_b=b.Lis->MoverCte(CteB,'p');(!err_b);err_b=b.Lis->MoverCte(CteB,'s'),comienzo++) {
for
(i=0,err=r.Lis->MoverCte(Cte,'p');i<comienzo;i++)
err=r.Lis->MoverCte(Cte,'s');
for
(err_a=a.Lis->MoverCte(CteA,'p');(!err_a);err_a=a.Lis->MoverCte(CteA,'s')) {
aux = b.Lis->ObtCte(CteB) *
a.Lis->ObtCte(CteA) + mellevo;
mellevo=aux / MAXBASE;
if
(err) {
cif=aux % MAXBASE +
mellevo2;
mellevo2=cif / MAXBASE;
r.Lis->InsDespues(Cte,cif
% MAXBASE);}
else
{
cif=r.Lis->ObtCte(Cte)
+ aux % MAXBASE + mellevo2;
mellevo2= cif / MAXBASE;
r.Lis->ModifCte(Cte,cif
% MAXBASE);
err=r.Lis->MoverCte(Cte,'s');}
}
if
((mellevo) || (mellevo2))
r.Lis->InsDespues(Cte,mellevo+mellevo2);
mellevo=mellevo2=0;
}
return(r);
}
BigNum operator / (const
BigNum & a, const BigNum & b)
{
double
signdivi=0, signresto;
signed char signoa=a.signo,signob=b.signo;
PNDoble CteA, CteB;
PNDoble CteResto = 0, CteCociente = 0;
TDato factor;
BigNum cociente,resto;
BigNum aux;
int
err,i,sale=0;
int
cantcif=0;
const_cast<BigNum&>(a).signo=const_cast<BigNum&>(b).signo=resto.signo=cociente.signo=1;
//Pongo todo positivo
//Toma las dos
cifras más significativas
if
(b.Lis->CantElem()<2)
i=b.Lis->CantElem();
else
i=2;
for(err=b.Lis->MoverCte(CteB,'u');(!err) &&
(i);i--,err=b.Lis->MoverCte(CteB,'a')) {
cantcif++;
signdivi+=pow(double(MAXBASE),i-1) * b.Lis->ObtCte(CteB);}
if
(cantcif==0)
return(0); //División por cero
devuelve 0 (convención)
for(err=a.Lis->MoverCte(CteA,'u');(!err);err=a.Lis->MoverCte(CteA,'a')) {
resto.Lis->MoverCte(CteResto,'p');
resto.Lis->InsAntes(CteResto,a.Lis->ObtCte(CteA));
if
(resto<b) {
if
(cociente.Lis->CantElem())
cociente.Lis->InsAntes(CteCociente,0);}
else
{
if
(resto.Lis->CantElem()>b.Lis->CantElem())
i=cantcif+1;
else
i=cantcif;
signresto=0;
for(err=resto.Lis->MoverCte(CteResto,'u');(!err) &&
(i);i--,err=resto.Lis->MoverCte(CteResto,'a'))
signresto+=pow(double(MAXBASE),i-1) * resto.Lis->ObtCte(CteResto);
factor=signresto/signdivi;
do
{
aux=factor * b;
if
(aux>resto)
factor--;
else
sale=1;}
while
(!sale);
resto-=aux;
cociente.Lis->InsAntes(CteCociente,factor);
} //Else
} // for
cociente.signo=signoa * signob;
return(cociente);
}
BigNum operator % (const
BigNum & a, const BigNum & b)
{
double
signdivi=0, signresto;
signed char signoa=a.signo,signob=b.signo;
PNDoble CteA, CteB;
PNDoble CteResto = 0, CteCociente = 0;
TDato factor;
BigNum cociente,resto;
BigNum aux;
int
err,i,sale=0;
int
cantcif=0;
const_cast<BigNum&>(a).signo=const_cast<BigNum&>(b).signo=resto.signo=cociente.signo=1;
//Pongo todo positivo
//Toma las dos
cifras más significativas
if
(b.Lis->CantElem()<2)
i=b.Lis->CantElem();
else
i=2;
for(err=b.Lis->MoverCte(CteB,'u');(!err) &&
(i);i--,err=b.Lis->MoverCte(CteB,'a')) {
cantcif++;
signdivi+=pow(double(MAXBASE),i-1) * b.Lis->ObtCte(CteB);}
if
(cantcif==0)
return(0); //División por cero
devuelve 0 (convención)
for(err=a.Lis->MoverCte(CteA,'u');(!err);err=a.Lis->MoverCte(CteA,'a')) {
resto.Lis->MoverCte(CteResto,'p');
resto.Lis->InsAntes(CteResto,a.Lis->ObtCte(CteA));
if
(resto<b) {
if
(cociente.Lis->CantElem())
cociente.Lis->InsAntes(CteCociente,
0);}
else
{
if
(resto.Lis->CantElem()>b.Lis->CantElem())
i=cantcif+1;
else
i=cantcif;
signresto=0;
for(err=resto.Lis->MoverCte(CteResto,'u');(!err) &&
(i);i--,err=resto.Lis->MoverCte(CteResto,'a'))
signresto+=pow(double(MAXBASE),i-1) *
resto.Lis->ObtCte(CteResto);
factor=signresto/signdivi;
do
{
aux=factor * b;
if
(aux>resto)
factor--;
else
sale=1;}
while
(!sale);
resto-=aux;
cociente.Lis->InsAntes(CteCociente,factor);
} //Else
} // for
resto.signo=signoa;
return(resto);
}
BigNum&
BigNum::operator++()
{
// BigNum r=*this;
PNDoble Cte;
if
(signo==-1) {
BigNum a;
signo=1;
(*this)--;
if
(!Lis->Vacia()) //Cero se considera positivo
signo=-1;}
else {
TDato cif,mellevo=1;
int
err=Lis->MoverCte(Cte,'p');
while
((!err) && (mellevo)) {
cif=Lis->ObtCte(Cte);
if
(cif==(MAXBASE-1)) {
Lis->ModifCte(Cte,0);
Lis->MoverCte(Cte,'s');}
else
{
Lis->ModifCte(Cte,cif+1);
mellevo=0;}
}
if
(mellevo)
Lis->InsDespues(Cte,1);}
return(*this);
}
BigNum&
BigNum::operator--()
{
// BigNum r=*this;
PNDoble Cte;
if
(signo==-1) {
BigNum a;
signo=1;
(*this)++;
signo=-1;}
else
{
TDato cif,mellevo=1;
int
err=Lis->MoverCte(Cte,'p');
while
((!err) && (mellevo)) {
cif=Lis->ObtCte(Cte);
if
(!cif) {
Lis->ModifCte(Cte,MAXBASE-1);
Lis->MoverCte(Cte,'s');}
else
{
Lis->ModifCte(Cte,cif-1);
mellevo=0;}
}
if
(Lis->Vacia()) //Era cero queda -1, signo negativo
signo=-1;
if
(mellevo)
Lis->InsDespues(Cte,1);
if
((Lis->CantElem()==1) && (Lis->ObtCte(Cte)==0))
Lis->Vaciar();
else
{
Lis->MoverCte(Cte,'u');
if
(Lis->ObtCte(Cte)==0)
Lis->ElimCte(Cte);
}
}
return(*this);
}
BigNum&
BigNum::operator +=(const
BigNum & a)
{
/* if (&a==this)
return((*this)*=2);*/
if
(a.signo!=signo) {
if
(a.signo==-1) {
const_cast<BigNum&>(a).signo=1;
(*this)-=a;
const_cast<BigNum&>(a).signo=-1;}
else
{
signo=1;
(*this)-=a;
signo*=-1;}
return(*this);}
TDato mellevo=0;
TMayor aux;
PNDoble Cte, CteA;
int
err=Lis->MoverCte(Cte,'p'),err_a=a.Lis->MoverCte(CteA,'p');
while
((!err) && (!err_a)) {
aux=Lis->ObtCte(Cte)+a.Lis->ObtCte(CteA)+mellevo;
Lis->ModifCte(Cte,aux % MAXBASE);
mellevo=aux / MAXBASE;
err=Lis->MoverCte(Cte,'s');
err_a=a.Lis->MoverCte(CteA,'s');}
if
(!err_a)
if
(mellevo)
if
(!err) {
Lis->MoverCte(Cte,'u');
Lis->InsDespues(Cte,mellevo);}
else
{
do
{
aux=Lis->ObtCte(Cte)+mellevo;
Lis->ModifCte(Cte,aux
% MAXBASE);
mellevo=aux /
MAXBASE;
err=Lis->MoverCte(Cte,'s');}
while
((!err) && (mellevo));}
else
if
(mellevo) {
do
{
aux=a.Lis->ObtCte(CteA)+mellevo;
Lis->InsDespues(Cte,aux
% MAXBASE);
mellevo=aux / MAXBASE;
err_a=a.Lis->MoverCte(CteA,'s');}
while
((!err_a) && (mellevo));}
while
(!err_a) {
Lis->InsDespues(Cte,a.Lis->ObtCte(CteA));
err_a=a.Lis->MoverCte(CteA,'s');}
if
(mellevo)
Lis->InsDespues(Cte,mellevo);
return(*this);
}
BigNum&
BigNum::operator-=(const
BigNum & a)
{
if
(&a==this) { //
si se resta a sí mismo da cero
Lis->Vaciar();
signo=1;
return(*this);}
if
(a.signo==-1) {
const_cast<BigNum&>(a).signo=1;
(*this)+=a;
const_cast<BigNum&>(a).signo=-1;
return(*this);}
else
if
(signo==-1) {
signo=1;
(*this)+=a;
signo=-1;
return(*this);}
PNDoble Cte, CteA;
if
(a>(*this))
(*this)=(*this)-a; //Si a es mayor debo hacer resta común
else {
TDato mellevo=0;
signed
long int aux;
int
err=Lis->MoverCte(Cte,'p'),err_a=a.Lis->MoverCte(CteA,'p');
while
(!err_a) {
aux=Lis->ObtCte(Cte)-a.Lis->ObtCte(CteA)-mellevo;
if
(aux<0) {
Lis->ModifCte(Cte,aux+MAXBASE);
mellevo=1;}
else
{
Lis->ModifCte(Cte,aux);
mellevo=0;}
Lis->MoverCte(Cte,'s');
err_a=a.Lis->MoverCte(CteA,'s');}
while
(mellevo) {
aux=Lis->ObtCte(Cte)-mellevo;
if
(aux<0) {
Lis->ModifCte(Cte,aux+MAXBASE);
mellevo=1;}
else
{
Lis->ModifCte(Cte,aux);
mellevo=0;}
Lis->MoverCte(Cte,'s');}
for
(err=Lis->MoverCte(Cte,'u');((!err)
&& (Lis->ObtCte(Cte)==0));err=Lis->MoverCte(Cte,'u'))
Lis->ElimCte(Cte); // Elimina los ceros que hubieran quedado a izquierda
}
return(*this);
}
BigNum&
BigNum::operator *=(const
BigNum & a)
{
*this=a*(*this);
return(*this);
}
BigNum&
BigNum::operator /=(const
BigNum & a)
{
*this=(*this)/a;
return(*this);
}
BigNum&
BigNum::operator %=(const
BigNum & a)
{
*this=(*this)%a;
return(*this);
}
#include "LDoble.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
LDoble::LDoble():Prim(0),Ult(0),CantNodos(0),
CantRefs(1)
{
}
LDoble::~LDoble()
{
CantRefs--;
if
(CantRefs==0)
Vaciar();
}
Boolean
LDoble::Vacia()
{
if
(Prim==0)
return(TRUE);
else
return(FALSE);
}
int
LDoble::MoverCte(PNDoble& Cte, char
direccion)
{
if
(Vacia()==FALSE) {
switch
(direccion) {
case
'p':Cte=Prim;
break;
case
'u':Cte=Ult;
break;
case
'a':if
(Cte->Ant==0)
return(1);
else
Cte=Cte->Ant;
break;
case
's':if
(Cte->Sig==0)
return(1);
else
Cte=Cte->Sig;
break;
default
: return(1);
break;
}
return(0);
}
else
{ Cte
= 0;
return(1);}
}
int
LDoble::InsAntes(PNDoble& Cte, TDato dat){
NDoble *p=new
NDoble;
p->Dato=dat;
p->Sig=Cte;
if
(Cte!=0)
if
(Cte->Ant==0) {
p->Ant=0;
Cte->Ant=p;
Prim=p;}
else
{
p->Ant=Cte->Ant;
Cte->Ant->Sig=p;
Cte->Ant=p;}
else{
Prim=p;
Ult=p;
p->Ant=0;
p->Sig=0;
}
Cte=p;
CantNodos++;
return(0);
}
int
LDoble::InsDespues(PNDoble& Cte, TDato dat){
NDoble *p=new
NDoble;
p->Dato=dat;
p->Ant=Cte;
if
(Cte!=0)
if
(Cte->Sig==0) {
p->Sig=0;
Cte->Sig=p;
Ult=p;}
else
{
p->Sig=Cte->Sig;
Cte->Sig->Ant=p;
Cte->Sig=p;}
else{
Prim=p;
Ult=p;
p->Ant=0;
p->Sig=0;
}
Cte=p;
CantNodos++;
return(0);
}
TDato
LDoble::ObtCte(PNDoble Cte){
return(Cte->Dato);}
int
LDoble::ModifCte(PNDoble& Cte, TDato dat){
if
(Cte!=0) {
Cte->Dato=dat;
return(0);}
else
return(1);
}
int
LDoble::ElimCte(PNDoble& Cte){
if
(Cte==0)
return(1);
else{
if
(Cte->Sig==0)
Ult=Cte->Ant;
else
Cte->Sig->Ant=Cte->Ant;
if
(Cte->Ant==0)
Prim=Cte->Sig;
else
Cte->Ant->Sig=Cte->Sig;
NDoble *p=Cte;
if
(Cte->Sig)
Cte=Cte->Sig;
else
Cte=Cte->Ant;
delete
p;
CantNodos--;
return(0);
}
}
void
LDoble::Vaciar() {
NDoble *p;
PNDoble Cte;
Cte=Prim;
while
(Cte) {
p=Cte;
Cte=p->Sig;
delete
p;
}
Prim=0;
Ult=0;
CantNodos=0;
}
int
LDoble::CantElem() {
return(CantNodos);
}
#include "ADH_test.h"
#include "rational.h"
#include "decimal.h"
/// Ambiente de prueba para la clase complicada para probar \c rational.
/// - No es necesario definir el método \c tearDown() pues para este
/// caso específico \c
TestFixture::tearDown() funciona bien.
template <class INT>
class
rational_TestFixture : public TestCase {
protected:
rational<INT> m_half, m_quarter,
m_one, m_eight, m_five;
public:
virtual void setUp(); ///<
Establece el ambiente de prueba
}; // rational_TestFixture
template <class INT>
void
rational_TestFixture<INT>::setUp() {
m_half.set(1,2);
m_quarter.set(1,4);
m_one.set(1);
m_eight.set(1,8);
m_five.set(1,5);
}
template <class INT>
class
rational_Test_Add : public
rational_TestFixture<INT> {
public:
bool run();
}; // rational_TestFixture
/// Función principal
/// - Requiere que recién haya sido ejecutado \c setUp()
template <class INT>
bool
rational_Test_Add<INT>::run() {
assertTrue( m_half+m_quarter ==
rational<INT>(30,40) );
assertTrue( rational<INT>(30,40) ==
m_quarter+m_half );
assertTrue( m_one+m_quarter ==
rational<INT>(125,100) );
assertTrue( rational<INT>(125,100) ==
m_quarter+m_one );
assertTrue(
rational<INT>(1,3) != rational<INT>(33,100) );
assertTrue( m_eight+m_five ==
rational<INT>(13,40) );
assertTrue( rational<INT>(13,40) ==
m_five+m_eight );
// Esto está aquí
sólo para destrozar los valores de *this
m_half = m_quarter = m_one = m_eight =
m_five = 0;
return
nError() == 0;
}
/// Clase para probar la resta de racionales.
template <class INT>
class
rational_Test_Substract : public
rational_TestFixture<INT> {
public:
bool run();
}; // rational_TestFixture
/// Función principal
/// - Requiere que recién haya sido ejecutado \c setUp()
template <class INT>
bool
rational_Test_Substract<INT>::run() {
assertTrue(
m_half-m_quarter == rational<INT>(10,40) );
assertTrue(
rational<INT>(-10,40) ==
m_quarter-m_half );
assertTrue(
m_one-m_quarter ==
rational<INT>(75,100) );
assertTrue(
rational<INT>(-75,100) == m_quarter-m_one );
assertEquals( rational<INT>(-3,4)
, m_quarter-m_one );
assertTrue( rational<INT>(75,100) ==
m_one-m_quarter );
assertTrue( m_eight-m_five ==
rational<INT>(-3,40) );
assertTrue( rational<INT>(3,40) ==
m_five-m_eight );
// Esto está aquí
sólo para destrozar los valores de *this
m_half = m_quarter = m_one = m_eight =
m_five = 0;
return
nError() == 0;
}
template <class INT>
class
rational_Test_Multiplication : public
rational_TestFixture<INT> {
public:
bool run();
}; // rational_TestFixture
/// Función principal
/// - Requiere que recién haya sido ejecutado \c setUp()
template <class INT>
bool
rational_Test_Multiplication<INT>::run() {
assertTrue( m_half * m_quarter ==
rational<INT>(10,80) );
assertTrue( rational<INT>(10,80) ==
m_quarter * m_half );
assertTrue( m_one * m_quarter ==
rational<INT>(10,40) );
assertTrue( rational<INT>(10,40) ==
m_quarter * m_one );
assertTrue(
rational<INT>(1,3) != rational<INT>(33,100) );
assertTrue( m_eight*m_five ==
rational<INT>(1,40) );
assertTrue( rational<INT>(1,40) ==
m_five*m_eight );
// Esto está aquí
sólo para destrozar los valores de *this
{ // 2^1024 * 3
^ 512;
INT deDOS=1, deTRES=1;
for (int i=0; i<1024; ++i ) {
INT elOTRO = (2 * deDOS);
assertTrue( deDOS < elOTRO );
deDOS = elOTRO;
}
for (int i=0; i<512; ++i ) {
deTRES *= 3;
}
assertTrue( mcd<INT>(deDOS, deTRES)
== 1 );
}
m_half = m_quarter = m_one = m_eight =
m_five = 0;
return
nError() == 0;
}
template <class INT>
class
rational_Test_Division : public
rational_TestFixture<INT> {
public:
bool run();
}; // rational_TestFixture
/// Función principal
/// - Requiere que recién haya sido ejecutado \c setUp()
template <class INT>
bool
rational_Test_Division<INT>::run() {
assertTrue( m_half/m_quarter ==
rational<INT>(4,2) );
assertTrue( ( rational<INT>(1,2) ) == (m_quarter/m_half) );
assertTrue( m_one/m_quarter ==
rational<INT>(4) );
assertTrue( rational<INT>(1,4) ==
m_quarter/m_one );
assertTrue(
rational<INT>(1,3) != rational<INT>(33,100) );
assertTrue( m_eight/m_five ==
rational<INT>(5,8) );
assertTrue( rational<INT>(8,5) ==
m_five/m_eight );
// Esto está aquí
sólo para destrozar los valores de *this
m_half = m_quarter = m_one = m_eight =
m_five = 0;
return
nError() == 0;
}
/// Programa principal desde donse se invocan todas las pruebas
int main() {
rational_Test_Add< decimal > rational_Test_Add_Instance;
cout << endl << endl << "1) Prueba directa con
\"TestFixture\"" << endl;
rational_Test_Add_Instance.setUp();
rational_Test_Add_Instance.run();
Report(cout, rational_Test_Add_Instance);
if
(rational_Test_Add_Instance.nError() != 0 ) {
cout << "El
error" << endl <<
rational_Test_Add_Instance.toString();
}
rational_Test_Substract< decimal
> rational_Test_Substract_Instance;
cout << endl << endl << "2) Prueba directa con
\"TestFixture\"" << endl;
rational_Test_Substract_Instance.setUp();
rational_Test_Substract_Instance.run();
Report(cout,
rational_Test_Substract_Instance);
if
(rational_Test_Substract_Instance.nError() != 0 ) {
cout << "El
error" << endl <<
rational_Test_Substract_Instance.toString();
}
rational_Test_Multiplication< decimal
>
rational_Test_Multiplication_Instance;
cout << endl << endl << "1) Prueba directa con
\"TestFixture\"" << endl;
rational_Test_Multiplication_Instance.setUp();
rational_Test_Multiplication_Instance.run();
Report(cout,
rational_Test_Multiplication_Instance);
if
(rational_Test_Multiplication_Instance.nError() != 0 ) {
cout << "El
error" << endl <<
rational_Test_Multiplication_Instance.toString();
}
rational_Test_Division< decimal
>
rational_Test_Division_Instance;
cout << endl << endl << "1) Prueba directa con \"TestFixture\""
<< endl;
rational_Test_Division_Instance.setUp();
rational_Test_Division_Instance.run();
Report(cout,
rational_Test_Division_Instance);
if
(rational_Test_Division_Instance.nError() != 0 ) {
cout << "El
error" << endl << rational_Test_Division_Instance.toString();
}
cin.get();
return 0;
}
http://www.di-mare.com/adolfo/cursos/2007-2/p2-ta-4.htm