git » metnum-tp1.git » commit ab0c74c

Agregar metodo de redondeo

author Rodrigo Campos
2010-09-05 18:29:02 UTC
committer Alberto Bertogli
2010-09-06 21:26:41 UTC
parent 9801172caa458bf93717be95bb7f07c8048ef405

Agregar metodo de redondeo

Ahora el constructor de numero toma como parametro tambien el metodo de
aproximacion. Por default es truncamiento, pero podria ser otro (como el de
redondeo implementado)

aritmetica.cpp +33 -8
aritmetica.hpp +13 -4

diff --git a/aritmetica.cpp b/aritmetica.cpp
index d90ea1f..c2fa0f0 100644
--- a/aritmetica.cpp
+++ b/aritmetica.cpp
@@ -36,15 +36,38 @@ double trunc(int prec, double n)
 	return to_double(t);
 }
 
+double round_up(int prec, double n)
+{
+	/* Sabemos que el double tiene 64 bits en total, de los cuales se usan
+	 * 52 para la mantisa. */
+
+	// Truncamos n
+	uint64_t t = to_u64(trunc(prec, n));
+
+	// Nos armamos el mismo numero truncado pero que tiene el 1 en el bit
+	// prec + 1
+	uint64_t to_round = t | (1 << (52 - prec - 1)) ;
+
+	// Nos armamos el double (normalizado, etc. porque la compu hace las
+	// cuentas) que tiene 1 en la posicion prec+1 de la mantisa
+	double to_round_d = to_double(to_round) - to_double(t);
+
+	// n + to_round_d es el ajuste que hay que hacer por redondeo a prec
+	// digitos. Como n + to_round_d ya esta redondeado a prec digitos,
+	// lo truncamos a prec digitos de precision
+	return trunc(prec, n + to_round_d);
+}
+
 
 /*
  * Clase nĂºmero
  */
 
-numero::numero(int prec, double real)
+numero::numero(int prec, double real, double (*aprox_meth)(int p, double n))
 {
 	this->prec = prec;
-	this->real = trunc(prec, real);
+	this->aprox_method = aprox_meth;
+	this->real = aprox_method(prec, real);
 }
 
 int numero::get_prec() const
@@ -58,25 +81,27 @@ int numero::get_prec() const
 	numero numero::operator OP (const numero &b) const \
 	{ \
 		return numero(this->prec, \
-				trunc(this->prec, this->real) \
+				this->aprox_method(this->prec, this->real) \
 					OP \
-				trunc(this->prec, b.real)); \
+				this->aprox_method(this->prec, b.real), \
+				this->aprox_method); \
 	} \
 	\
 	numero numero::operator OP (const double &b) const \
 	{ \
 		return numero(this->prec, \
-				trunc(this->prec, this->real) \
+				this->aprox_method(this->prec, this->real) \
 					OP \
-				trunc(this->prec, b)); \
+				this->aprox_method(this->prec, b), \
+				this->aprox_method); \
 	} \
 	\
 	numero operator OP (const double &a, const numero &b) \
 	{ \
 		return numero(b.get_prec(), \
-				trunc(b.get_prec(), a) \
+				b.aprox_method(b.get_prec(), a) \
 					OP \
-				b.to_double() ); \
+				b.to_double(), b.aprox_method); \
 	}
 
 DEF_OP(+)
diff --git a/aritmetica.hpp b/aritmetica.hpp
index 5bd8f79..ed41c20 100644
--- a/aritmetica.hpp
+++ b/aritmetica.hpp
@@ -8,11 +8,18 @@
 #define print_64t "ll"
 #endif
 
+/* Recorta la precision del double dado, devuelve un double "recortado". */
+double trunc(int prec, double n);
+
+/* Redondea el doble dado fijadonse si el bit prec + 1 de la mantisa es mayor o
+ * no a cero */
+double round_up(int prec, double n);
+
 class numero
 {
 public:
-	numero(int prec = 52, double real = 0);
-
+	numero(int prec = 52, double real = 0, double (*aprox_meth)(int p,
+				double n) = trunc);
 	// Aritmeticas
 	numero operator + (const numero &b) const;
 	numero operator - (const numero &b) const;
@@ -37,6 +44,10 @@ public:
 	// Devolver la precision
 	int get_prec() const;
 
+	// Metodo usado para aproximar a la precision pedida (truncamiento,
+	// redondeo, etc.)
+	double (*aprox_method) (int prec, double n);
+
 private:
 	// Precision
 	int prec;
@@ -61,8 +72,6 @@ uint64_t to_u64(numero n);
  * pavote. */
 double to_double(uint64_t n);
 
-/* Recorta la precision del double dado, devuelve un double "recortado". */
-double trunc(int prec, double n);
 
 
 #endif // ifdef _ARITMETICA_HPP