+
+ParanoidNumber & ParanoidNumber::operator+=(const ParanoidNumber & a)
+{
+ delete Operation(new ParanoidNumber(a), ADD);
+ return *this;
+}
+
+
+ParanoidNumber & ParanoidNumber::operator-=(const ParanoidNumber & a)
+{
+ delete Operation(new ParanoidNumber(a), SUBTRACT);
+ return *this;
+}
+
+ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a)
+{
+ delete Operation(new ParanoidNumber(a), MULTIPLY);
+ return *this;
+}
+
+
+ParanoidNumber & ParanoidNumber::operator/=(const ParanoidNumber & a)
+{
+ delete Operation(new ParanoidNumber(a), DIVIDE);
+ return *this;
+}
+
+/**
+ * Performs the operation on a with argument b (a += b, a -= b, a *= b, a /= b)
+ * @returns b if b can safely be deleted
+ * @returns NULL if b has been merged with a
+ * append indicates that b should be merged
+ */
+ParanoidNumber * ParanoidNumber::Operation(ParanoidNumber * b, Optype op, ParanoidNumber ** parent)
+{
+ if (b == NULL)
+ return NULL;
+
+ Optype invop = InverseOp(op); // inverse of p
+ ParanoidNumber * append_at = this;
+
+ if (Floating())
+ {
+ if ((op == ADD || op == SUBTRACT) && (m_value == 0))
+ {
+ m_value = b->m_value;
+ for (int i = 0; i < NOP; ++i)
+ {
+ m_next[i] = b->m_next[i];
+ b->m_next[i] = NULL;
+ }
+ return b;
+ }
+ if ((op == MULTIPLY) && (m_value == 1))
+ {
+ m_value = b->m_value;
+ for (int i = 0; i < NOP; ++i)
+ {
+ m_next[i] = b->m_next[i];
+ b->m_next[i] = NULL;
+ }
+ return b;
+ return b;
+ }
+
+ }
+
+ if (b->Floating())
+ {
+ if ((op == ADD || op == SUBTRACT) && (b->m_value == 0))
+ return b;
+ if ((op == MULTIPLY || op == DIVIDE) && (b->m_value == 1))
+ return b;
+ }
+
+ // Operation can be applied directly to the m_value of this and b
+ // ie: op is + or - and this and b have no * or / children
+ // or: op is * or / and this and b have no + or - children
+ if (Pure(op) && (b->Pure(op)))
+ {
+ if (ParanoidOp<digit_t>(m_value, b->m_value, op)) // op applied successfully...
+ {
+ Simplify(op);
+ Simplify(invop);
+ for (int i = 0; i < NOP; ++i) // Try applying b's children to this
+ {
+ delete Operation(b->m_next[i], Optype(i));
+ b->m_next[i] = NULL;
+ }
+ return b; // can delete b
+ }
+ }
+
+ // Try to simplify the cases:
+ // a + b*c == (a/c + b)*c
+ // a + b/c == (a*c + b)/c
+ else if ((op == ADD || op == SUBTRACT) &&
+ (Pure(op) || b->Pure(op)))
+ {
+
+ Debug("Simplify: {%s} %c {%s}", Str().c_str(), OpChar(op), b->Str().c_str());
+ Optype adj[] = {MULTIPLY, DIVIDE};
+ for (int i = 0; i < 2; ++i)
+ {
+
+ Optype f = adj[i];
+ Optype invf = InverseOp(f);
+
+ Debug("Try %c", OpChar(f));
+
+ if (m_next[f] == NULL && b->m_next[f] == NULL)
+ continue;
+
+ ParanoidNumber * tmp_a = new ParanoidNumber(*this);
+ ParanoidNumber * tmp_b = new ParanoidNumber(*b);
+
+
+ ParanoidNumber * af = (tmp_a->m_next[f] != NULL) ? new ParanoidNumber(*(tmp_a->m_next[f])) : NULL;
+ ParanoidNumber * bf = (tmp_b->m_next[f] != NULL) ? new ParanoidNumber(*(tmp_b->m_next[f])) : NULL;
+
+ Debug("{%s} %c {%s}", tmp_a->Str().c_str(), OpChar(op), tmp_b->Str().c_str());
+ Debug("{%s} %c {%s}", tmp_a->Str().c_str(), OpChar(op), tmp_b->Str().c_str());
+ if (tmp_a->Operation(af, invf) != af || tmp_b->Operation(bf, invf) != bf)
+ {
+ delete af;
+ delete bf;
+ delete tmp_a;
+ delete tmp_b;
+ continue;
+ }
+ Debug("{%s} %c {%s}", tmp_a->Str().c_str(), OpChar(op), tmp_b->Str().c_str());
+
+ if (tmp_a->Operation(bf, invf) == bf && tmp_b->Operation(af, invf) == af) // a / c simplifies
+ {
+ if (tmp_a->Operation(tmp_b, op) != NULL) // (a/c) + b simplifies
+ {
+ this->operator=(*tmp_a);
+ if (bf != NULL)
+ delete Operation(bf, f);
+ if (af != NULL)
+ delete Operation(af, f);
+ delete tmp_a;
+ delete tmp_b;
+ return b; // It simplified after all!
+ }
+ else
+ {
+ tmp_b = NULL;
+ delete af;
+ delete bf;
+ }
+ }
+ //Debug("tmp_a : %s", tmp_a->PStr().c_str());
+ //Debug("tmp_b : %s", tmp_b->PStr().c_str());
+ delete tmp_a;
+ delete tmp_b;
+ }
+ }
+
+ // See if operation can be applied to children of this in the same dimension
+ {
+ // (a / b) / c = a / (b*c)
+ // (a * b) / c = a * (b/c)
+ // (a / b) * c = a / (b/c)
+ // (a * b) * c = a * (b*c)
+ // (a + b) + c = a + (b+c)
+ // (a - b) + c = a - (b-c)
+ // (a + b) - c = a + (b-c)
+ // (a - b) - c = a - (b+c)
+ Optype fwd(op);
+ Optype rev(invop);
+ if (op == DIVIDE || op == SUBTRACT)
+ {
+ fwd = invop;
+ rev = op;
+ }
+ // opposite direction first (because ideally things will cancel each other out...)
+ if (m_next[invop] != NULL && m_next[invop]->Operation(b, rev, &append_at) != NULL)
+ return b;
+ // forward direction
+ if (m_next[op] != NULL && m_next[op]->Operation(b, fwd, &append_at) != NULL)
+ return b;
+ }
+
+ // At this point, we have no choice but to merge 'b' with this ParanoidNumber
+
+ // we are a child; the merge operation needs to be applied by the root, so leave
+ if (parent != NULL)
+ {
+ if (m_next[op] == NULL)
+ *parent = this; // last element in list
+ return NULL;
+ }
+
+ append_at->m_next[op] = b; // Merge with b
+
+ // MULTIPLY and DIVIDE operations need to be performed on each term in the ADD/SUBTRACT dimension
+ if (op == DIVIDE || op == MULTIPLY)
+ {
+ // apply the operation to each term
+ if (m_next[ADD] != NULL) delete m_next[ADD]->Operation(new ParanoidNumber(*b), op);
+ if (m_next[SUBTRACT] != NULL) delete m_next[SUBTRACT]->Operation(new ParanoidNumber(*b), op);
+
+ // try and simplify this by adding the terms (you never know...)
+ Simplify(ADD);
+ Simplify(SUBTRACT);
+ }
+ // failed to simplify
+ return NULL;
+}
+
+bool ParanoidNumber::Simplify(Optype op)
+{
+ ParanoidNumber * n = m_next[op];
+ m_next[op] = NULL;
+ if (Operation(n, Optype(op)))
+ {
+ delete n;
+ return true;
+ }
+ else
+ {
+ m_next[op] = n;
+ return false;
+ }
+}
+
+string ParanoidNumber::PStr() const
+{
+ stringstream s;
+ for (int i = 0; i < NOP; ++i)
+ {
+ Optype f = Optype(i);
+ s << this << OpChar(f) << m_next[f] << "\n";
+ }
+ return s.str();
+}
+
+
+
+
+