Add MPFRC++ mpreal type
authorSam Moore <matches@ucc.asn.au>
Wed, 10 Sep 2014 04:45:00 +0000 (12:45 +0800)
committerSam Moore <matches@ucc.asn.au>
Wed, 10 Sep 2014 04:45:00 +0000 (12:45 +0800)
It's slow but less slow than Rationals.

Project complete.

Haha I wish.

16 files changed:
src/Makefile
src/bezier.h
src/document.cpp
src/main.h
src/objectrenderer.cpp
src/paranoidnumber.cpp
src/paranoidnumber.h
src/path.cpp
src/path.h
src/real.cpp
src/real.h
src/tests/calculator.cpp
src/tests/fecalculator.cpp
src/tests/paranoidcalculator.cpp
src/tests/paranoidtester.cpp [new file with mode: 0644]
src/view.cpp

index 630f979..1e4d83f 100644 (file)
@@ -9,7 +9,7 @@ QT_INCLUDE := -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/qt4/QtCor
 QT_DEF := -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB
 QT_LIB :=  -L/usr/lib/x86_64-linux-gnu -lQtGui -lQtCore -lpthread 
 
-LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL -lgmp $(QT_LIB)
+LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL -lmpfr -lgmp $(QT_LIB)
 LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL -lgmp
 LIB_i686 = $(LIB_i386)
 
index cfe5808..2b0c1e1 100644 (file)
@@ -279,7 +279,7 @@ namespace IPDF
                        {
                                Real ptx, pty;
                                Evaluate(ptx, pty, t);
-                               Debug("Root: t = %f, (%f,%f)", t, ptx, pty);
+                               Debug("Root: t = %f, (%f,%f)", Double(t), Double(ptx), Double(pty));
                        }
                        
                        std::vector<Bezier> all_beziers;
index d097600..d825914 100644 (file)
@@ -301,6 +301,7 @@ unsigned Document::AddPath(unsigned start_index, unsigned end_index, const Colou
        unsigned data_index = AddPathData(path);
        Rect bounds = path.SolveBounds(m_objects);
        unsigned result = Add(PATH, bounds,data_index);
+       //Debug("Added path %u -> %u (%u objects) colour {%u,%u,%u,%u}, stroke {%u,%u,%u,%u}", start_index, end_index, (end_index - start_index), fill.r, fill.g, fill.b, fill.a, stroke.r, stroke.g, stroke.b, stroke.a);
        return result;
 }
 
@@ -1008,7 +1009,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca
        {
                AddPath(start_index, end_index);
        }
-       Debug("Added Glyph \"%c\" at %f %f, scale %f", (char)character, Float(x), Float(y), Float(scale));
+       //Debug("Added Glyph \"%c\" at %f %f, scale %f", (char)character, Float(x), Float(y), Float(scale));
 
        stbtt_FreeShape(font, instructions);
 }
index 88aebfe..3de819c 100644 (file)
@@ -23,6 +23,7 @@ inline void OverlayBMP(Document & doc, const char * input, const char * output,
 }
 
 // It is the only way.
+// Dear god what have I done
 void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view)
 {
        static bool oldButtonDown = false;
@@ -52,7 +53,7 @@ void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view)
        }
        if (buttons)
        {
-               #if REAL >= REAL_RATIONAL
+               #if REAL == REAL_RATIONAL
                        view->Translate(Real(oldx, scr->ViewportWidth()) -Real(x,scr->ViewportWidth()), Real(oldy, scr->ViewportHeight()) - Real(y,scr->ViewportHeight()));
                #else                   
                        view->Translate(Real(oldx-x)/Real(scr->ViewportWidth()), Real(oldy-y)/Real(scr->ViewportHeight()));
@@ -68,7 +69,7 @@ void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view)
                
        if (wheel)
        {
-               #if REAL >= REAL_RATIONAL
+               #if REAL == REAL_RATIONAL
                        view->ScaleAroundPoint(Real(x,scr->ViewportWidth()), Real(y,scr->ViewportHeight()), Real(20-wheel, 20));
                #else
                        view->ScaleAroundPoint(Real(x)/Real(scr->ViewportWidth()),Real(y)/Real(scr->ViewportHeight()), Real(expf(-wheel/20.f)));
index a6bb77d..8f4c55f 100644 (file)
@@ -384,7 +384,7 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP
                
                Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
                PixelBounds pix_bounds(bounds);
-               const Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
+               Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
                
                if (view.ShowingFillPoints())
                {
@@ -407,10 +407,11 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP
                
                if (pix_bounds.w*pix_bounds.h > 100)
                {
+                       vector<Vec2> & fill_points = path.FillPoints(objects, view);
                        Debug("High resolution; use fill points %u,%u", pix_bounds.w, pix_bounds.h);
-                       for (unsigned f = 0; f < path.m_fill_points.size(); ++f)
+                       for (unsigned f = 0; f < fill_points.size(); ++f)
                        {
-                               PixelPoint fill_point(CPUPointLocation(path.m_fill_points[f], view, target));
+                               PixelPoint fill_point(CPUPointLocation(fill_points[f], view, target));
                                
                                FloodFillOnCPU(fill_point.first, fill_point.second, pix_bounds, target, path.m_fill, path.m_stroke);
                        }
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;
 }
 
index 4c481bd..a2e8542 100644 (file)
@@ -5,6 +5,9 @@
 #include <cfloat>
 #include <map>
 #include <string>
+#include "log.h"
+
+
 
 namespace IPDF
 {
@@ -13,34 +16,52 @@ namespace IPDF
                public:
                        typedef enum {ADD, SUBTRACT, MULTIPLY, DIVIDE} Optype;
                        
-                       ParanoidNumber(float value=0, Optype type = ADD) : m_value(value), m_op(type), m_next(NULL)
+                       ParanoidNumber(float value=0, Optype type = ADD) : m_value(value), m_op(type), m_next_term(NULL), m_next_factor(NULL)
                        {
                                
                        }
                        
-                       ParanoidNumber(const ParanoidNumber & cpy) : m_value(cpy.m_value), m_op(cpy.m_op), m_next(NULL)
+                       ParanoidNumber(const ParanoidNumber & cpy) : m_value(cpy.m_value), m_op(cpy.m_op), m_next_term(NULL), m_next_factor(NULL)
                        {
-                               if (cpy.m_next != NULL)
+                               if (cpy.m_next_term != NULL)
                                {
-                                       m_next = new ParanoidNumber(*(cpy.m_next));
+                                       m_next_term = new ParanoidNumber(*(cpy.m_next_term));
+                               }
+                               if (cpy.m_next_factor != NULL)
+                               {
+                                       m_next_factor = new ParanoidNumber(*(cpy.m_next_factor));
                                }
                        }
                        
-                       ParanoidNumber(const ParanoidNumber & cpy, Optype type) : ParanoidNumber(cpy)
+                       ParanoidNumber(const ParanoidNumber & cpy, Optype type) : m_value(cpy.m_value), m_op(type), m_next_term(NULL), m_next_factor(NULL)
                        {
-                               m_op = type;
+                               if (cpy.m_next_term != NULL)
+                               {
+                                       m_next_term = new ParanoidNumber(*(cpy.m_next_term));
+                               }
+                               if (cpy.m_next_factor != NULL)
+                               {
+                                       m_next_factor = new ParanoidNumber(*(cpy.m_next_factor));
+                               }
                        }
                        
                        ParanoidNumber(const char * str);
+                       ParanoidNumber(const std::string & str) : ParanoidNumber(str.c_str()) {}
                        
                        virtual ~ParanoidNumber()
                        {
-                               if (m_next != NULL)
-                                       delete m_next;
+                               if (m_next_term != NULL)
+                                       delete m_next_term;
+                               if (m_next_factor != NULL)
+                                       delete m_next_factor;
                        }
                        
+                       template <class T> T Convert() const;
+                       double ToDouble() const {return Convert<double>();}
+                       float ToFloat() const {return Convert<float>();}
                        
-                       double ToDouble() const;
+                       bool Floating() const {return (m_next_term == NULL && m_next_factor == NULL);}
+                       bool Sunken() const {return !Floating();} // I could not resist...
                        
                        ParanoidNumber & operator+=(const ParanoidNumber & a);
                        ParanoidNumber & operator-=(const ParanoidNumber & a);
@@ -82,15 +103,24 @@ namespace IPDF
                        }
                        
                        std::string Str() const;
+                       static char OpChar(Optype op) 
+                       {
+                               static char opch[] = {'+','-','*','/'};
+                               return opch[(int)op];
+                       }
                
                private:
                        void Simplify();
-                       ParanoidNumber * InsertAfter(ParanoidNumber * insert);
-                       ParanoidNumber * InsertAfter(float value, Optype op);
+                       void SimplifyTerms();
+                       void SimplifyFactors();
+                       
                        
                        float m_value;
                        Optype m_op;
-                       ParanoidNumber * m_next;
+                       ParanoidNumber * m_next_term;
+                       ParanoidNumber * m_next_factor;
+                       
+                       
 
                        
                        
@@ -98,6 +128,43 @@ namespace IPDF
        };
 
 
+template <class T>
+T ParanoidNumber::Convert() const
+{
+       T value = (m_op == SUBTRACT) ? -m_value : m_value;
+       const ParanoidNumber * n = m_next_factor;
+       if (n != NULL)
+       {
+               switch (n->m_op)
+               {
+                       case MULTIPLY:
+                               value *= n->Convert<T>();
+                               break;
+                       case DIVIDE:
+                               value /= n->Convert<T>();
+                               break;
+                       default:
+                               Fatal("Shouldn't happen");
+                               break;
+               }
+       }
+       n = m_next_term;
+       if (n != NULL)
+       {
+               switch (n->m_op)
+               {
+                       case ADD:
+                       case SUBTRACT:
+                               value += n->Convert<T>();
+                               break;
+                       default:
+                               Fatal("Shouldn't happen");
+               }
+       }
+       return value;
+}
+
+
 }
 
 #endif //_PARANOIDNUMBER_H
index c58d3df..589c509 100644 (file)
@@ -43,68 +43,14 @@ Path::Path(const Objects & objects, unsigned start, unsigned end, const Colour &
                {
                        ymax = (objb.y+objb.h);
                        bottom = i;
-               }
-               
-               // find fill points
-               Vec2 pt;
-               // left
-               pt = Vec2(objb.x, objb.y+objb.h/Real(2));
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               // right
-               pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2));
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               // bottom
-               pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h);
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               // top
-               pt = Vec2(objb.x+objb.w/Real(2), objb.y);
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-                       
-               // topleft
-               pt = Vec2(objb.x, objb.y);
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               // topright
-               pt = Vec2(objb.x+objb.w, objb.y);
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               // bottom left
-               pt = Vec2(objb.x, objb.y+objb.h);
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               // bottom right
-               pt = Vec2(objb.x+objb.w, objb.y);
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-                       
-               // mid
-               pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2));
-               if (PointInside(objects, pt))
-                       m_fill_points.push_back(pt);
-               
-               
+               }       
        }
        
        // Get actual turning point coords of the 4 edge case beziers
        m_top = objects.beziers[objects.data_indices[top]].ToAbsolute(objects.bounds[top]).GetTop();
        m_bottom = objects.beziers[objects.data_indices[bottom]].ToAbsolute(objects.bounds[bottom]).GetBottom();
        m_left = objects.beziers[objects.data_indices[left]].ToAbsolute(objects.bounds[left]).GetLeft();
-       m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();
-       
-       Vec2 pt = (m_top + m_bottom)/2;
-       if (PointInside(objects, pt))
-               m_fill_points.push_back(pt);
-       pt = (m_left + m_right)/2;
-       if (PointInside(objects, pt))
-               m_fill_points.push_back(pt);
-       pt = (m_left + m_right + m_top + m_bottom)/4;
-       if (PointInside(objects, pt))
-               m_fill_points.push_back(pt);
-               
+       m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();    
 }
 
 
@@ -166,6 +112,73 @@ bool Path::PointInside(const Objects & objects, const Vec2 & pt, bool debug) con
        return true;
 }
 
+vector<Vec2> & Path::FillPoints(const Objects & objects, const View & view)
+{
+       if (m_fill_points.size() != 0)
+               return m_fill_points;
+               
+       
+       for (unsigned i = m_start; i <= m_end; ++i)
+       {
+               const Rect & objb = objects.bounds[i];
+               // find fill points
+               Vec2 pt;
+               // left
+               pt = Vec2(objb.x, objb.y+objb.h/Real(2));
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               // right
+               pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2));
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               // bottom
+               pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h);
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               // top
+               pt = Vec2(objb.x+objb.w/Real(2), objb.y);
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+                       
+               // topleft
+               pt = Vec2(objb.x, objb.y);
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               // topright
+               pt = Vec2(objb.x+objb.w, objb.y);
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               // bottom left
+               pt = Vec2(objb.x, objb.y+objb.h);
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               // bottom right
+               pt = Vec2(objb.x+objb.w, objb.y);
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+                       
+               // mid
+               pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2));
+               if (PointInside(objects, pt))
+                       m_fill_points.push_back(pt);
+               
+               
+       }
+       
+       // 4 extrema
+       Vec2 pt = (m_top + m_bottom)/2;
+       if (PointInside(objects, pt))
+               m_fill_points.push_back(pt);
+       pt = (m_left + m_right)/2;
+       if (PointInside(objects, pt))
+               m_fill_points.push_back(pt);
+       pt = (m_left + m_right + m_top + m_bottom)/4;
+       if (PointInside(objects, pt))
+               m_fill_points.push_back(pt);
+               
+       return m_fill_points;
+}
+
 Rect Path::SolveBounds(const Objects & objects) const
 {
                return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
index 1a0ed53..fa63cb4 100644 (file)
@@ -22,12 +22,14 @@ namespace IPDF
        };
        
        class Objects;
+       class View;
        
        struct Path
        {
                Path(const Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(128,128,128,255), const Colour & _stroke = Colour(0,0,0,0));
                
                Rect SolveBounds(const Objects & objects) const;
+               std::vector<Vec2> & FillPoints(const Objects & objects, const View & view);
                
                // Is point inside shape?
                bool PointInside(const Objects & objects, const Vec2 & pt, bool debug=false) const;
index 0f104e5..aa0cfc8 100644 (file)
@@ -9,7 +9,8 @@ namespace IPDF
                "long double",
                "VFPU",
                "Rational<int64_t>", 
-               "Rational<Arbint>"
+               "Rational<Arbint>",
+               "mpfrc++ real"
        };
        
 #if REAL == REAL_RATIONAL_ARBINT
index 0cbc05d..b107649 100644 (file)
@@ -11,6 +11,7 @@
 #define REAL_VFPU 3
 #define REAL_RATIONAL 4
 #define REAL_RATIONAL_ARBINT 5
+#define REAL_MPFRCPP 6
 
 #ifndef REAL
        #error "REAL was not defined!"
        #include "gmpint.h"
 #endif //REAL
 
+#if REAL == REAL_MPFRCPP
+       #include <mpreal.h>
+#endif //REAL
+
 namespace IPDF
 {      
        extern const char * g_real_name[];
@@ -56,7 +61,13 @@ namespace IPDF
        inline double Double(const Real & r) {return r.ToDouble();}
        inline int64_t Int64(const Real & r) {return r.ToInt64();}
        inline Rational<ARBINT> Sqrt(const Rational<ARBINT> & r) {return r.Sqrt();}
-
+#elif REAL == REAL_MPFRCPP
+       typedef mpfr::mpreal Real;
+       inline double Double(const Real & r) {return r.toDouble();}
+       inline float Float(const Real & r) {return r.toDouble();}
+       inline int64_t Int64(const Real & r) {return r.toLong();}
+       inline Real Sqrt(const Real & r) {return mpfr::sqrt(r, mpfr::mpreal::get_default_rnd());}
+       inline Real Abs(const Real & r) {return mpfr::abs(r, mpfr::mpreal::get_default_rnd());}
 #else
        #error "Type of Real unspecified."
 #endif //REAL
index 89009f1..ab100b9 100644 (file)
@@ -11,7 +11,7 @@ using namespace IPDF;
 
 int main(int argc, char ** argv)
 {
-       while (true)
+       while (cin.good())
        {
                double da; double db;
                char op;
index 2ae39d9..c16265c 100644 (file)
@@ -17,7 +17,7 @@ int main(int argc, char ** argv)
        Debug("FLT_MIN = %.40f", FLT_MIN);
        Debug("FLT_EPSILON = %.40f", FLT_EPSILON);
        
-       while (true)
+       while (cin.good())
        {
                float a; float b;
                char op;
index 171eaf0..9c5a88a 100644 (file)
@@ -19,17 +19,29 @@ int main(int argc, char ** argv)
        Debug("FLT_EPSILON = %.40f", FLT_EPSILON);
        
        ParanoidNumber a("0.3");
-       Debug("start at %s", a.Str().c_str());
+       Debug("start at {%s} = %lf", a.Str().c_str(), a.ToDouble());
        cout << "0.3 ";
        float fa = 0.3;
        double da = 0.3;
        while (cin.good())
        {
                char op;
-               double db;
-               cin >> op >> db;
-               float fb(db);
-               ParanoidNumber b(fb);
+               cin >> op;
+               string token("");
+               for (char c = cin.peek(); cin.good() && !iswspace(c); c = cin.peek())
+               {
+                       if (c == '+' || c == '-' || c == '*' || c == '/')
+                       {
+                               break;
+                       }
+                       token += c;
+                       c = cin.get();
+               }
+               Debug("String is %s", token.c_str());
+               float fb = strtof(token.c_str(), NULL);
+               double db = strtod(token.c_str(), NULL);
+               ParanoidNumber b(token.c_str());
+               Debug("b is {%s} %lf", b.Str().c_str(), b.ToDouble());
                switch (op)
                {
                        case '+':
diff --git a/src/tests/paranoidtester.cpp b/src/tests/paranoidtester.cpp
new file mode 100644 (file)
index 0000000..bf1dc0b
--- /dev/null
@@ -0,0 +1,99 @@
+#include "main.h"
+#include "real.h"
+#include <cmath>
+#include <cassert>
+#include <list>
+#include <bitset>
+#include <iostream>
+#include <cfloat>
+#include <fenv.h>
+#include "paranoidnumber.h"
+
+using namespace std;
+using namespace IPDF;
+
+string RandomNumberAsString(int digits = 6)
+{
+       string result("");
+       int dp = 1+(rand() % 3);
+       for (int i = 0; i < digits; ++i)
+       {
+               if (i == dp)
+               {
+                       result += ".";
+                       continue;
+               }
+               result += ('0'+rand() % 10);
+       }
+       return result;
+}
+
+#define TEST_CASES 10000
+
+int main(int argc, char ** argv)
+{
+
+       string number(RandomNumberAsString());
+       ParanoidNumber a(number);
+       float fa = strtof(number.c_str(), NULL);
+       double da = strtod(number.c_str(), NULL);
+       long double lda = strtold(number.c_str(), NULL);
+       
+       if (fabs(a.ToDouble() - da) > 1e-6)
+       {
+               Error("double %lf, pn %lf {%s}", da, a.ToDouble(), a.Str().c_str());
+               Fatal("Didn't construct correctly off %s", number.c_str());
+       }
+       
+       char opch[] = {'+','-','*','/'};
+       
+       for (int i = 0; i < TEST_CASES; ++i)
+       {
+               number = RandomNumberAsString();
+               ParanoidNumber b(number);
+               float fb = strtof(number.c_str(), NULL);
+               double db = strtod(number.c_str(), NULL);
+               long double ldb = strtold(number.c_str(), NULL);
+               int op = (rand() % 4);
+               ParanoidNumber olda(a);
+               double oldda(da);
+               switch (op)
+               {
+                       case 0:
+                               a += b;
+                               fa += fb;
+                               da += db;
+                               lda += ldb;
+                               break;
+                       case 1:
+                               a -= b;
+                               fa -= fb;
+                               da -= db;
+                               lda -= ldb;
+                               break;
+                       case 2:
+                               a *= b;
+                               fa *= fb;
+                               da *= db;
+                               lda *= ldb;
+                               break;
+                       case 3:
+                               a /= b;
+                               fa /= fb;
+                               da /= db;
+                               lda /= ldb;
+                               break;
+               }
+               if (fabs(a.ToDouble() - da) > 1.0 )
+               {
+                       Error("Op %i: ParanoidNumber probably doesn't work", i);
+                       Error("Operation: %lf %c %lf", oldda, opch[op], db);
+                       Error("As PN: %lf %c %lf", olda.ToDouble(), opch[op], b.ToDouble());
+                       Fatal("%lf, expected aboout %lf", a.ToDouble(), da);
+               }
+       }
+       printf("ParanoidNumber: {%s} = %.40lf\n", a.Str().c_str(), a.ToDouble());
+       printf("float: %.40f\n", fa);
+       printf("double: %.40lf\n", da);
+       printf("long double: %.40Lf\n", lda);
+}
index 925fa47..60f2976 100644 (file)
@@ -264,6 +264,7 @@ void View::Render(int width, int height)
 #ifndef CONTROLPANEL_DISABLED
        ControlPanel::Update();
 #endif //CONTROLPANEL_DISABLED
+       //Debug("Completed Render");
        
 }
 

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