Merge branch 'master' of git.ucc.asn.au:ipdf/code
[ipdf/code.git] / src / paranoidnumber.cpp
1 #include "paranoidnumber.h"
2
3 #include <sstream>
4 #include <fenv.h>
5 #include "log.h"
6 #include <iostream>
7
8 using namespace std;
9 namespace IPDF
10 {
11         
12
13 ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next_term(NULL), m_next_factor(NULL)
14 {
15         int dp = 0;
16         int end = 0;
17         while (str[dp] != '\0' && str[dp] != '.')
18         {
19                 ++dp;
20                 ++end;
21         }
22         while (str[end] != '\0')
23                 ++end;
24                 
25         ParanoidNumber m(1);
26         for (int i = dp-1; i >= 0; --i)
27         {
28                 ParanoidNumber b(str[i]-'0');
29                 b*=m;
30                 //Debug("m is %s", m.Str().c_str());
31                 //Debug("Add %s", b.Str().c_str());
32                 this->operator+=(b);
33                 //Debug("Now at %s", Str().c_str());
34                 m*=10;
35         }
36         ParanoidNumber n(1);
37         for (int i = dp+1; i < end; ++i)
38         {
39                 n/=10;
40                 ParanoidNumber b(str[i]-'0');
41                 //Debug("%s * %s", b.Str().c_str(), n.Str().c_str());
42                 b*=n;
43                 //Debug("b -> %s", b.Str().c_str());
44                 //Debug("Add %s", b.Str().c_str());
45                 this->operator+=(b);
46                 //Debug("Now at %s", Str().c_str());
47
48         }
49         Debug("Constructed {%s} from %s (%f)", Str().c_str(), str, ToDouble()); 
50 }
51
52 ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a)
53 {
54         //TODO: Optimise
55         delete m_next_term;
56         delete m_next_factor;
57         m_op = a.m_op;
58         if (a.m_next_term != NULL)
59         {
60                 m_next_term = new ParanoidNumber(*(a.m_next_term));
61         }
62         if (a.m_next_factor != NULL)
63         {
64                 m_next_factor = new ParanoidNumber(*(a.m_next_factor));
65         }
66         return *this;
67 }
68
69 ParanoidNumber & ParanoidNumber::operator+=(const ParanoidNumber & a)
70 {
71         // this = v + t + (a)
72         // -> v + (a) + t
73         
74         ParanoidNumber * nt = m_next_term;
75         ParanoidNumber * nf = m_next_factor;
76         
77         ParanoidNumber ca(a);
78         if (m_next_factor != NULL)
79         {
80                 if (m_next_factor->m_op == MULTIPLY)
81                         ca /= (*m_next_factor);
82                 else
83                         ca *= (*m_next_factor);
84                         
85                 if (ca.Floating())
86                 {
87                         m_next_factor = NULL;
88                         m_next_term = NULL;
89                         operator+=(ca);
90                         m_next_factor = nf;
91                         m_next_term = nt;
92                         Simplify();
93                         return *this;
94                 }
95                 
96         }
97         
98         m_next_term = new ParanoidNumber(a, ADD);
99         ParanoidNumber * t = m_next_term;
100         while (t->m_next_term != NULL)
101                 t = t->m_next_term;
102         t->m_next_term = nt;
103         //Debug("Simplify {%s} after add", Str().c_str());
104         Simplify();
105         return *this;
106 }
107
108 ParanoidNumber & ParanoidNumber::operator-=(const ParanoidNumber & a)
109 {
110         // this = v + t + (a)
111         // -> v + (a) + t
112         
113         ParanoidNumber * nt = m_next_term;
114         ParanoidNumber * nf = m_next_factor;
115         
116         ParanoidNumber ca(a, SUBTRACT);
117         if (m_next_factor != NULL)
118         {
119                 if (m_next_factor->m_op == MULTIPLY)
120                         ca /= (*m_next_factor);
121                 else
122                         ca *= (*m_next_factor);
123                         
124                 if (ca.Floating())
125                 {
126                         m_next_factor = NULL;
127                         m_next_term = NULL;
128                         operator-=(ca);
129                         m_next_factor = nf;
130                         m_next_term = nt;
131                         Simplify();
132                         return *this;
133                 }
134                 
135         }
136         
137         m_next_term = new ParanoidNumber(a,SUBTRACT);
138         ParanoidNumber * t = m_next_term;
139         while (t->m_next_term != NULL)
140         {
141                 t->m_op = SUBTRACT;
142                 t = t->m_next_term;
143         }
144         t->m_op = SUBTRACT;
145         //Debug("next term {%s}", m_next_term->Str().c_str());
146         t->m_next_term = nt;
147         //Debug("Simplify {%s} after sub", Str().c_str());
148         Simplify();
149         return *this;
150 }
151
152 ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a)
153 {
154         Debug("{%s} *= {%s}", Str().c_str(), a.Str().c_str());
155         // this = (vf + t) * (a)
156         ParanoidNumber * nf = m_next_factor;
157         m_next_factor = new ParanoidNumber(a, MULTIPLY);
158         ParanoidNumber * t = m_next_factor;
159         while (t->m_next_factor != NULL)
160                 t = t->m_next_factor;
161         t->m_next_factor = nf;
162         if (m_next_term != NULL)
163                 m_next_term->operator*=(a);
164         //Debug("Simplify after mul");
165         Debug("Simplify {%s}", Str().c_str());
166         Simplify();
167         return *this;
168 }
169
170
171 ParanoidNumber & ParanoidNumber::operator/=(const ParanoidNumber & a)
172 {
173         //Debug("Called %s /= %s", Str().c_str(), a.Str().c_str());
174         // this = (vf + t) * (a)
175         ParanoidNumber * nf = m_next_factor;
176         m_next_factor = new ParanoidNumber(a, DIVIDE);
177         ParanoidNumber * t = m_next_factor;
178         while (t->m_next_factor != NULL)
179                 t = t->m_next_factor;
180         t->m_next_factor = nf;
181         if (m_next_term != NULL)
182                 m_next_term->operator/=(a);
183         Simplify();
184         return *this;
185 }
186
187
188
189 void ParanoidNumber::SimplifyTerms()
190
191         //Debug("Simplify {%s}", Str().c_str()); 
192         if (m_next_term == NULL)
193         {
194                 //Debug("No terms!");
195                 return;
196         }
197
198         for (ParanoidNumber * a = this; a != NULL; a = a->m_next_term)
199         {
200                 ParanoidNumber * bprev = a;
201                 ParanoidNumber * b = a->m_next_term;
202                 while (b != NULL)
203                 {
204                         //Debug("Simplify factors of %s", b->Str().c_str());
205                         b->SimplifyFactors();
206                         if (b->m_next_factor != NULL)
207                         {
208                                 bprev = b;
209                                 b = b->m_next_term;
210                                 continue;
211                         }
212                         float f = a->m_value;
213                         feclearexcept(FE_ALL_EXCEPT);
214                         switch (b->m_op)
215                         {
216                                 case ADD:
217                                         f += b->m_value;
218                                         break;
219                                 case SUBTRACT:
220                                         f -= b->m_value;
221                                         break;
222                                 default:
223                                         Fatal("Unexpected %c in term list...", OpChar(b->m_op));
224                                         break;
225                         }
226                         if (!fetestexcept(FE_ALL_EXCEPT))
227                         {
228                                 a->m_value = f;
229                                 bprev->m_next_term = b->m_next_term;
230                                 b->m_next_term = NULL;
231                                 delete b;
232                                 b = bprev;
233                         }
234                         bprev = b;
235                         b = b->m_next_term;
236                 }
237         }
238 }
239
240 void ParanoidNumber::SimplifyFactors()
241
242         //Debug("Simplify {%s}", Str().c_str()); 
243         if (m_next_factor == NULL)
244         {
245                 //Debug("No factors!");
246                 return;
247         }
248
249         for (ParanoidNumber * a = this; a != NULL; a = a->m_next_factor)
250         {
251                 ParanoidNumber * bprev = a;
252                 ParanoidNumber * b = a->m_next_factor;
253                 while (b != NULL)
254                 {
255                         b->SimplifyTerms();
256                         if (b->m_next_term != NULL)
257                         {
258                                 bprev = b;
259                                 b = b->m_next_factor;
260                                 continue;
261                         }
262                         float f = a->m_value;
263                         feclearexcept(FE_ALL_EXCEPT);
264                         switch (b->m_op)
265                         {
266                                 case MULTIPLY:
267                                         if (a->m_op != DIVIDE) 
268                                                 f *= b->m_value;
269                                         else
270                                                 f /= b->m_value;
271                                         break;
272                                 case DIVIDE:
273                                         if (a->m_op != DIVIDE)
274                                                 f /= b->m_value;
275                                         else
276                                                 f *= b->m_value;
277                                         break;
278                                 default:
279                                         Fatal("Unexpected %c in factor list...",OpChar(b->m_op));
280                                         break;
281                         }
282                         if (!fetestexcept(FE_ALL_EXCEPT))
283                         {
284                                 
285                                 a->m_value = f;
286                                 bprev->m_next_factor = b->m_next_factor;
287                                 b->m_next_factor = NULL;
288                                 delete b;
289                                 b = bprev;
290                         }
291                         //else
292                                 //Debug("Failed to simplify %f %c %f", a->m_value, OpChar(b->m_op), b->m_value);
293                         bprev = b;
294                         b = b->m_next_factor;
295                 }
296         }
297 }
298
299 void ParanoidNumber::Simplify()
300 {
301         SimplifyFactors();
302         SimplifyTerms();
303 }
304
305 string ParanoidNumber::Str() const
306 {
307         string result("");
308         stringstream s;
309         
310         s << m_value;
311         
312         if (m_next_factor != NULL)
313         {
314                 result += OpChar(m_op);
315                 result += "(";
316                 result += s.str();
317                 result += m_next_factor->Str();
318                 result += ")";
319         }
320         else
321         {
322                 result += OpChar(m_op);
323                 result += s.str();
324         }
325                 
326         if (m_next_term != NULL)
327         {
328                 result += " ";
329                 result += m_next_term->Str();
330         }
331         return result;
332 }
333
334 }

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