Add MPFRC++ mpreal type
[ipdf/code.git] / src / paranoidnumber.cpp
index 2510f66..2bb44da 100644 (file)
@@ -3,13 +3,14 @@
 #include <sstream>
 #include <fenv.h>
 #include "log.h"
+#include <iostream>
 
 using namespace std;
 namespace IPDF
 {
        
 
-ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next(NULL)
+ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next_term(NULL), m_next_factor(NULL)
 {
        int dp = 0;
        int end = 0;
@@ -26,7 +27,10 @@ ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next
        {
                ParanoidNumber b(str[i]-'0');
                b*=m;
+               //Debug("m is %s", m.Str().c_str());
+               //Debug("Add %s", b.Str().c_str());
                this->operator+=(b);
+               //Debug("Now at %s", Str().c_str());
                m*=10;
        }
        ParanoidNumber n(1);
@@ -34,142 +38,131 @@ ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next
        {
                n/=10;
                ParanoidNumber b(str[i]-'0');
+               //Debug("%s * %s", b.Str().c_str(), n.Str().c_str());
                b*=n;
+               //Debug("b -> %s", b.Str().c_str());
+               //Debug("Add %s", b.Str().c_str());
                this->operator+=(b);
-       }
-       
-}
+               //Debug("Now at %s", Str().c_str());
 
-ParanoidNumber * ParanoidNumber::InsertAfter(float value, Optype op)
-{
-       return InsertAfter(new ParanoidNumber(value, op));
-}
-       
-ParanoidNumber * ParanoidNumber::InsertAfter(ParanoidNumber * insert)
-{
-       //Debug("Insert {%s} after {%f, %s}",insert->Str().c_str(),
-       //      m_value, g_opstr[m_op]);
-       ParanoidNumber * n = m_next;
-       m_next = insert;
-       
-       ParanoidNumber * p = m_next;
-       while (p->m_next != NULL)
-               p = p->m_next;
-       p->m_next = n;
-       
-       return m_next;
+       }
+       Debug("Constructed {%s} from %s (%f)", Str().c_str(), str, ToDouble()); 
 }
 
-
 ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a)
 {
-       const ParanoidNumber * na = &a;
-       ParanoidNumber * nb = this;
-       ParanoidNumber * p = NULL;
-       while (na != NULL && nb != NULL)
+       //TODO: Optimise
+       delete m_next_term;
+       delete m_next_factor;
+       m_op = a.m_op;
+       if (a.m_next_term != NULL)
        {
-               nb->m_value = na->m_value;
-               nb->m_op = na->m_op;
-               na = na->m_next;
-               p = nb;
-               nb = nb->m_next;
-               
-       }       
-       
-       while (na != NULL) // => nb == NULL
-       {
-               InsertAfter(na->m_value, na->m_op);
-               na = na->m_next;
+               m_next_term = new ParanoidNumber(*(a.m_next_term));
        }
-
-       if (nb != NULL)
+       if (a.m_next_factor != NULL)
        {
-               if (p != NULL)
-                       p->m_next = NULL;
-               delete nb;
+               m_next_factor = new ParanoidNumber(*(a.m_next_factor));
        }
        return *this;
 }
 
 ParanoidNumber & ParanoidNumber::operator+=(const ParanoidNumber & a)
 {
-       ParanoidNumber * insert = new ParanoidNumber(a, ADD);
-       if (m_next == NULL || m_next->m_op == ADD || m_next->m_op == SUBTRACT)
-       {
-               InsertAfter(insert);
-               Simplify();
-               return *this;
-       }
+       // this = v + t + (a)
+       // -> v + (a) + t
        
-       if (m_next->m_op == MULTIPLY) // (a*b) + c == (a+[c/b]) * b
-               insert->operator/=(*m_next);
-       else
-               insert->operator*=(*m_next); // (a/b) + c == (a+[c*b])/b
+       ParanoidNumber * nt = m_next_term;
+       ParanoidNumber * nf = m_next_factor;
        
-       if (insert->m_next != NULL) // neither of the above simplified
-       {
-               //Debug("{%s} did not simplify, change back to {%s}", insert->Str().c_str(), a.Str().c_str());
-               insert->operator=(a); // Just add as is
-               insert->m_op = ADD;
-               ParanoidNumber * n = this;
-               while (n->m_next != NULL)
-                       n = n->m_next;
-               n->InsertAfter(insert);
-       }
-       else
+       ParanoidNumber ca(a);
+       if (m_next_factor != NULL)
        {
-               InsertAfter(insert);
+               if (m_next_factor->m_op == MULTIPLY)
+                       ca /= (*m_next_factor);
+               else
+                       ca *= (*m_next_factor);
+                       
+               if (ca.Floating())
+               {
+                       m_next_factor = NULL;
+                       m_next_term = NULL;
+                       operator+=(ca);
+                       m_next_factor = nf;
+                       m_next_term = nt;
+                       Simplify();
+                       return *this;
+               }
+               
        }
+       
+       m_next_term = new ParanoidNumber(a, ADD);
+       ParanoidNumber * t = m_next_term;
+       while (t->m_next_term != NULL)
+               t = t->m_next_term;
+       t->m_next_term = nt;
+       //Debug("Simplify {%s} after add", Str().c_str());
        Simplify();
        return *this;
 }
+
 ParanoidNumber & ParanoidNumber::operator-=(const ParanoidNumber & a)
 {
-       ParanoidNumber * insert = new ParanoidNumber(a, SUBTRACT);
-       if (m_next == NULL || m_next->m_op == ADD || m_next->m_op == SUBTRACT)
-       {
-               InsertAfter(insert);
-               Simplify();
-               return *this;
-       }
+       // this = v + t + (a)
+       // -> v + (a) + t
        
-       if (m_next->m_op == MULTIPLY) // (a*b) - c == (a-[c/b]) * b
-               insert->operator/=(*m_next);
-       else
-               insert->operator*=(*m_next); // (a/b) - c == (a-[c*b])/b
+       ParanoidNumber * nt = m_next_term;
+       ParanoidNumber * nf = m_next_factor;
        
-       if (insert->m_next != NULL) // neither of the above simplified
+       ParanoidNumber ca(a, SUBTRACT);
+       if (m_next_factor != NULL)
        {
-               //Debug("{%s} did not simplify, change back to {%s}", insert->Str().c_str(), a.Str().c_str());
-               insert->operator=(a); // Just add as is
-               insert->m_op = SUBTRACT;
-               ParanoidNumber * n = this;
-               while (n->m_next != NULL)
-                       n = n->m_next;
-               n->InsertAfter(insert);
-       }       
-       else
+               if (m_next_factor->m_op == MULTIPLY)
+                       ca /= (*m_next_factor);
+               else
+                       ca *= (*m_next_factor);
+                       
+               if (ca.Floating())
+               {
+                       m_next_factor = NULL;
+                       m_next_term = NULL;
+                       operator-=(ca);
+                       m_next_factor = nf;
+                       m_next_term = nt;
+                       Simplify();
+                       return *this;
+               }
+               
+       }
+       
+       m_next_term = new ParanoidNumber(a,SUBTRACT);
+       ParanoidNumber * t = m_next_term;
+       while (t->m_next_term != NULL)
        {
-               InsertAfter(insert);
+               t->m_op = SUBTRACT;
+               t = t->m_next_term;
        }
+       t->m_op = SUBTRACT;
+       //Debug("next term {%s}", m_next_term->Str().c_str());
+       t->m_next_term = nt;
+       //Debug("Simplify {%s} after sub", Str().c_str());
        Simplify();
        return *this;
 }
 
 ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a)
 {
-       ParanoidNumber * n = m_next;
-       while (n != NULL)
-       {
-               if (n->m_op == ADD || n->m_op == SUBTRACT)
-               {
-                       n->operator*=(a);
-                       break;
-               }
-               n = n->m_next;
-       }
-               
-       InsertAfter(new ParanoidNumber(a, MULTIPLY));
+       Debug("{%s} *= {%s}", Str().c_str(), a.Str().c_str());
+       // this = (vf + t) * (a)
+       ParanoidNumber * nf = m_next_factor;
+       m_next_factor = new ParanoidNumber(a, MULTIPLY);
+       ParanoidNumber * t = m_next_factor;
+       while (t->m_next_factor != NULL)
+               t = t->m_next_factor;
+       t->m_next_factor = nf;
+       if (m_next_term != NULL)
+               m_next_term->operator*=(a);
+       //Debug("Simplify after mul");
+       Debug("Simplify {%s}", Str().c_str());
        Simplify();
        return *this;
 }
@@ -177,122 +170,164 @@ ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a)
 
 ParanoidNumber & ParanoidNumber::operator/=(const ParanoidNumber & a)
 {
-       ParanoidNumber * n = m_next;
-       while (n != NULL)
-       {
-               if (n->m_op == ADD || n->m_op == SUBTRACT)
-               {
-                       n->operator/=(a);
-                       break;
-               }
-               n = n->m_next;
-       }
-               
-       InsertAfter(new ParanoidNumber(a, DIVIDE));
+       //Debug("Called %s /= %s", Str().c_str(), a.Str().c_str());
+       // this = (vf + t) * (a)
+       ParanoidNumber * nf = m_next_factor;
+       m_next_factor = new ParanoidNumber(a, DIVIDE);
+       ParanoidNumber * t = m_next_factor;
+       while (t->m_next_factor != NULL)
+               t = t->m_next_factor;
+       t->m_next_factor = nf;
+       if (m_next_term != NULL)
+               m_next_term->operator/=(a);
        Simplify();
        return *this;
 }
 
-double ParanoidNumber::ToDouble() const
-{
-       double value = (m_op == SUBTRACT) ? -m_value : m_value;
-       const ParanoidNumber * n = m_next;
-       while (n != NULL)
+
+
+void ParanoidNumber::SimplifyTerms()
+{ 
+       //Debug("Simplify {%s}", Str().c_str()); 
+       if (m_next_term == NULL)
        {
-               switch (n->m_op)
+               //Debug("No terms!");
+               return;
+       }
+
+       for (ParanoidNumber * a = this; a != NULL; a = a->m_next_term)
+       {
+               ParanoidNumber * bprev = a;
+               ParanoidNumber * b = a->m_next_term;
+               while (b != NULL)
                {
-                       case ADD:
-                       case SUBTRACT:
-                               return value + n->ToDouble();
-                               break;
-                       case MULTIPLY:
-                               value *= n->m_value;
-                               break;
-                       case DIVIDE:
-                               value /= n->m_value;
-                               break;
+                       //Debug("Simplify factors of %s", b->Str().c_str());
+                       b->SimplifyFactors();
+                       if (b->m_next_factor != NULL)
+                       {
+                               bprev = b;
+                               b = b->m_next_term;
+                               continue;
+                       }
+                       float f = a->m_value;
+                       feclearexcept(FE_ALL_EXCEPT);
+                       switch (b->m_op)
+                       {
+                               case ADD:
+                                       f += b->m_value;
+                                       break;
+                               case SUBTRACT:
+                                       f -= b->m_value;
+                                       break;
+                               default:
+                                       Fatal("Unexpected %c in term list...", OpChar(b->m_op));
+                                       break;
+                       }
+                       if (!fetestexcept(FE_ALL_EXCEPT))
+                       {
+                               a->m_value = f;
+                               bprev->m_next_term = b->m_next_term;
+                               b->m_next_term = NULL;
+                               delete b;
+                               b = bprev;
+                       }
+                       bprev = b;
+                       b = b->m_next_term;
                }
-               n = n->m_next;
        }
-       return value;
 }
 
-void ParanoidNumber::Simplify()
-{
-       ParanoidNumber * n = m_next;
-       ParanoidNumber * p = this;
-       
-       while (n != NULL)
+void ParanoidNumber::SimplifyFactors()
+{ 
+       //Debug("Simplify {%s}", Str().c_str()); 
+       if (m_next_factor == NULL)
        {
-               
-               float a = p->m_value;
-               switch (n->m_op)
+               //Debug("No factors!");
+               return;
+       }
+
+       for (ParanoidNumber * a = this; a != NULL; a = a->m_next_factor)
+       {
+               ParanoidNumber * bprev = a;
+               ParanoidNumber * b = a->m_next_factor;
+               while (b != NULL)
                {
-                       case ADD:
-                               n->Simplify();
-                               feclearexcept(FE_ALL_EXCEPT);
-                               a += n->m_value;
-                               break;
-                       case SUBTRACT:
-                               n->Simplify();
-                               feclearexcept(FE_ALL_EXCEPT);
-                               a -= n->m_value;
-                               break;
-                       case MULTIPLY:
-                               feclearexcept(FE_ALL_EXCEPT);
-                               a *= n->m_value;
-                               break;
-                       case DIVIDE:
-                               feclearexcept(FE_ALL_EXCEPT);
-                               a /= n->m_value;
-                               break;
+                       b->SimplifyTerms();
+                       if (b->m_next_term != NULL)
+                       {
+                               bprev = b;
+                               b = b->m_next_factor;
+                               continue;
+                       }
+                       float f = a->m_value;
+                       feclearexcept(FE_ALL_EXCEPT);
+                       switch (b->m_op)
+                       {
+                               case MULTIPLY:
+                                       if (a->m_op != DIVIDE) 
+                                               f *= b->m_value;
+                                       else
+                                               f /= b->m_value;
+                                       break;
+                               case DIVIDE:
+                                       if (a->m_op != DIVIDE)
+                                               f /= b->m_value;
+                                       else
+                                               f *= b->m_value;
+                                       break;
+                               default:
+                                       Fatal("Unexpected %c in factor list...",OpChar(b->m_op));
+                                       break;
+                       }
+                       if (!fetestexcept(FE_ALL_EXCEPT))
+                       {
                                
+                               a->m_value = f;
+                               bprev->m_next_factor = b->m_next_factor;
+                               b->m_next_factor = NULL;
+                               delete b;
+                               b = bprev;
+                       }
+                       //else
+                               //Debug("Failed to simplify %f %c %f", a->m_value, OpChar(b->m_op), b->m_value);
+                       bprev = b;
+                       b = b->m_next_factor;
                }
-               // can't merge p and n
-               if (fetestexcept(FE_ALL_EXCEPT))
-               {
-                       while (n != NULL && n->m_op != ADD && n->m_op != SUBTRACT)
-                               n = n->m_next;
-                       if (n != NULL)
-                               n->Simplify();
-                       return;
-               }
-               else
-               {
-                       //  merge n into p
-                       p->m_value = a;
-                       p->m_next = n->m_next;
-                       n->m_next = NULL;
-                       delete n;
-                       n = p->m_next;          
-               }
-               //Debug("  -> {%s}", Str().c_str());
        }
 }
 
+void ParanoidNumber::Simplify()
+{
+       SimplifyFactors();
+       SimplifyTerms();
+}
+
 string ParanoidNumber::Str() const
 {
        string result("");
-       switch (m_op)
+       stringstream s;
+       
+       s << m_value;
+       
+       if (m_next_factor != NULL)
        {
-               case ADD:
-                       result += " +";
-                       break;
-               case SUBTRACT:
-                       result += " -";
-                       break;
-               case MULTIPLY:
-                       result += " *";
-                       break;
-               case DIVIDE:
-                       result += " /";
-                       break;
+               result += OpChar(m_op);
+               result += "(";
+               result += s.str();
+               result += m_next_factor->Str();
+               result += ")";
+       }
+       else
+       {
+               result += OpChar(m_op);
+               result += s.str();
+       }
+               
+       if (m_next_term != NULL)
+       {
+               result += " ";
+               result += m_next_term->Str();
        }
-       stringstream s("");
-       s << m_value;
-       result += s.str();
-       if (m_next != NULL)
-               result += m_next->Str();
        return result;
 }
 

UCC git Repository :: git.ucc.asn.au