X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=blobdiff_plain;f=src%2Fparanoidnumber.cpp;h=60802eb432a7acc0f17c530a42bf7b0461c17f0b;hp=82c7ba453b7830738eef11319d5321151195b01c;hb=64b7c42c71c35d520424cf4ca5ecaa99faef8b26;hpb=03cc1b0a0d0705e0b1d92e13fdb18608c7a00272 diff --git a/src/paranoidnumber.cpp b/src/paranoidnumber.cpp index 82c7ba4..60802eb 100644 --- a/src/paranoidnumber.cpp +++ b/src/paranoidnumber.cpp @@ -6,6 +6,8 @@ #include #include +// here be many copy paste bugs + using namespace std; namespace IPDF { @@ -27,14 +29,20 @@ ParanoidNumber::~ParanoidNumber() ParanoidNumber::ParanoidNumber(const string & str) : m_value(0), m_next() { #ifdef PARANOID_SIZE_LIMIT - m_size = 0; + m_size = 1; #endif #ifdef PARANOID_CACHE_RESULTS - m_cached_result = NAN; + m_cache_valid = false; #endif int dp = 0; int end = 0; + bool negate = str[0] == '-'; + if (negate) + { + dp++; + end++; + } while (str[dp] != '\0' && str[dp] != '.') { ++dp; @@ -43,7 +51,7 @@ ParanoidNumber::ParanoidNumber(const string & str) : m_value(0), m_next() while (str[end] != '\0') ++end; ParanoidNumber m(1); - for (int i = dp-1; i >= 0; --i) + for (int i = dp-1; i >= negate; --i) { ParanoidNumber b(str[i]-'0'); b*=m; @@ -58,6 +66,14 @@ ParanoidNumber::ParanoidNumber(const string & str) : m_value(0), m_next() b*=n; this->operator+=(b); } + + if (negate) + Negate(); + + #ifdef PARANOID_COMPARE_EPSILON + double d = strtod(str.c_str(), NULL); + CompareForSanity(d, d); + #endif } ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a) @@ -69,8 +85,9 @@ ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a) #endif m_value = a.m_value; - #ifdef PARANOID_CACHE_RESULT + #ifdef PARANOID_CACHE_RESULTS m_cached_result = a.m_cached_result; + m_cache_valid = a.m_cache_valid; #endif for (int i = 0; i < NOP; ++i) { @@ -80,20 +97,9 @@ ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a) for (auto n : a.m_next[i]) m_next[i].push_back(new ParanoidNumber(*n)); } - /* - for (unsigned j = 0; j < m_next[i].size() && j < a.m_next[i].size(); ++j) - { - if (a.m_next[i][j] != NULL) - m_next[i][j]->operator=(*(a.m_next[i][j])); - } - - for (unsigned j = a.m_next[i].size(); j < m_next[i].size(); ++j) - { - delete m_next[i][j]; - } - m_next[i].resize(a.m_next[i].size()); - */ - //} + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(a.Digit(),a.Digit()); + #endif return *this; } @@ -273,88 +279,148 @@ bool TrustingOp(int8_t & a, const int8_t & b, Optype op) ParanoidNumber & ParanoidNumber::operator+=(const digit_t & a) { - - //assert(this != NULL); + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare += a; + #endif delete Operation(new ParanoidNumber(a), ADD); - Simplify(ADD); Simplify(SUBTRACT); + Simplify(ADD); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator-=(const digit_t & a) { + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare -= a; + #endif delete Operation(new ParanoidNumber(a), SUBTRACT); - Simplify(SUBTRACT); Simplify(ADD); + Simplify(SUBTRACT); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator*=(const digit_t & a) { + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare *= a; + #endif delete Operation(new ParanoidNumber(a), MULTIPLY); + Simplify(DIVIDE); Simplify(MULTIPLY); - Simplify(DIVIDE); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator/=(const digit_t & a) { + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare /= a; + #endif delete Operation(new ParanoidNumber(a), DIVIDE); Simplify(MULTIPLY); Simplify(DIVIDE); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator+=(const ParanoidNumber & a) { - - //assert(this != NULL); + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare += a.Digit(); + #endif delete Operation(new ParanoidNumber(a), ADD); - Simplify(ADD); Simplify(SUBTRACT); + Simplify(ADD); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a.Digit()); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator-=(const ParanoidNumber & a) { + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare -= a.Digit(); + #endif delete Operation(new ParanoidNumber(a), SUBTRACT); - Simplify(SUBTRACT); Simplify(ADD); + Simplify(SUBTRACT); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a.Digit()); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a) { + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare *= a.Digit(); + #endif delete Operation(new ParanoidNumber(a), MULTIPLY); + Simplify(DIVIDE); Simplify(MULTIPLY); - Simplify(DIVIDE); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a.Digit()); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator/=(const ParanoidNumber & a) { + #ifdef PARANOID_COMPARE_EPSILON + digit_t compare = Digit(); + compare /= a.Digit(); + #endif delete Operation(new ParanoidNumber(a), DIVIDE); Simplify(MULTIPLY); Simplify(DIVIDE); + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(compare, a.Digit()); + #endif return *this; } ParanoidNumber & ParanoidNumber::operator=(const digit_t & a) { + for (int i = 0; i < NOP; ++i) { for (auto n : m_next[i]) delete n; + m_next[i].clear(); } m_value = a; - #ifdef PARANOID_CACHE_RESULT + #ifdef PARANOID_CACHE_RESULTS m_cached_result = a; + m_cache_valid = true; + #endif + + #ifdef PARANOID_COMPARE_EPSILON + CompareForSanity(a,a); #endif + return *this; } @@ -363,15 +429,21 @@ ParanoidNumber * ParanoidNumber::OperationTerm(ParanoidNumber * b, Optype op, Pa { ////assert(b->SanityCheck()); #ifdef PARANOID_CACHE_RESULTS - m_cached_result = NAN; + m_cache_valid = false; #endif #ifdef PARANOID_SIZE_LIMIT - if (m_size > PARANOID_SIZE_LIMIT) + if (m_size + b->m_size >= PARANOID_SIZE_LIMIT) { + this->operator=(this->Digit()); if (op == ADD) m_value += b->Digit(); else m_value -= b->Digit(); + m_size = 1; + #ifdef PARANOID_CACHE_RESULTS + m_cached_result = m_value; + m_cache_valid = true; + #endif return b; } //Debug("At size limit %d", m_size); @@ -474,7 +546,7 @@ ParanoidNumber * ParanoidNumber::OperationTerm(ParanoidNumber * b, Optype op, Pa //merge->m_next[*merge_op].push_back(b); m_next[op].push_back(b); #ifdef PARANOID_SIZE_LIMIT - m_size += 1+b->m_size; + m_size += b->m_size; #endif } else @@ -493,20 +565,25 @@ ParanoidNumber * ParanoidNumber::OperationTerm(ParanoidNumber * b, Optype op, Pa ParanoidNumber * ParanoidNumber::OperationFactor(ParanoidNumber * b, Optype op, ParanoidNumber ** merge_point, Optype * merge_op) { - //assert(SanityCheck()); - //assert(b->SanityCheck()); #ifdef PARANOID_CACHE_RESULTS - m_cached_result = NAN; + m_cache_valid = false; #endif #ifdef PARANOID_SIZE_LIMIT - if (m_size > PARANOID_SIZE_LIMIT) + if (m_size + b->m_size >= PARANOID_SIZE_LIMIT) { + this->operator=(this->Digit()); if (op == MULTIPLY) m_value *= b->Digit(); else m_value /= b->Digit(); - //Debug("At size limit %d", m_size); + m_size = 1; + #ifdef PARANOID_CACHE_RESULTS + m_cached_result = m_value; + m_cache_valid = true; + #endif + //Debug("Cut off %p", this); return b; + } #endif @@ -530,7 +607,11 @@ ParanoidNumber * ParanoidNumber::OperationFactor(ParanoidNumber * b, Optype op, } if (b->Floating() && b->m_value == 1) return b; - + if (b->Floating() && b->m_value == 0 && op == MULTIPLY) + { + operator=(*b); + return b; + } if (NoTerms() && b->NoTerms()) @@ -617,7 +698,7 @@ ParanoidNumber * ParanoidNumber::OperationFactor(ParanoidNumber * b, Optype op, delete(sub->OperationFactor(new ParanoidNumber(*cpy_b), op)); #ifdef PARANOID_SIZE_LIMIT - m_size += 1+b->m_size; + m_size += b->m_size; #endif } //assert(SanityCheck()); @@ -710,7 +791,7 @@ bool ParanoidNumber::Simplify(Optype op) if (result != NULL) { #ifdef PARANOID_SIZE_LIMIT - m_size -= (1+result->m_size); + m_size -= result->m_size; #endif *m = NULL; delete(result); @@ -727,7 +808,7 @@ bool ParanoidNumber::Simplify(Optype op) #ifdef PARANOID_SIZE_LIMIT if (Operation(n, op) == n) { - m_size -= (1+n->m_size); + m_size -= n->m_size; delete n; } #else @@ -765,10 +846,11 @@ ParanoidNumber::digit_t ParanoidNumber::Digit() const // Get around the absurd requirement that const correctness be observed. #ifdef PARANOID_CACHE_RESULTS + if (m_cache_valid) // le sigh ambiguous function compiler warnings + return m_cached_result; + digit_t & result = ((ParanoidNumber*)(this))->m_cached_result; - if (!isnan(float(result))) // le sigh ambiguous function compiler warnings - return result; #else digit_t result; #endif @@ -785,6 +867,10 @@ ParanoidNumber::digit_t ParanoidNumber::Digit() const result += add->Digit(); for (auto sub : m_next[SUBTRACT]) result -= sub->Digit(); + + #ifdef PARANOID_CACHE_RESULTS + ((ParanoidNumber*)(this))->m_cache_valid = true; + #endif return result; } @@ -846,10 +932,24 @@ bool ParanoidNumber::SanityCheck(set & visited) const { if (!div->SanityCheck(visited)) return false; + if (div->Digit() == 0) + { + Error("Divide by zero"); + return false; + } } return true; } +void ParanoidNumber::Negate() +{ + swap(m_next[ADD], m_next[SUBTRACT]); + m_value = -m_value; + #ifdef PARANOID_CACHE_RESULTS + m_cached_result = -m_cached_result; + #endif +} + #ifdef PARANOID_USE_ARENA void * ParanoidNumber::operator new(size_t s)