author | Rodrigo Campos
<rodrigo@sdfg.com.ar> 2010-09-05 18:29:02 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2010-09-06 21:26:41 UTC |
parent | 9801172caa458bf93717be95bb7f07c8048ef405 |
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