2510f66388cfce8f5431009c9887a330522f2974
[ipdf/code.git] / src / paranoidnumber.cpp
1 #include "paranoidnumber.h"
2
3 #include <sstream>
4 #include <fenv.h>
5 #include "log.h"
6
7 using namespace std;
8 namespace IPDF
9 {
10         
11
12 ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next(NULL)
13 {
14         int dp = 0;
15         int end = 0;
16         while (str[dp] != '\0' && str[dp] != '.')
17         {
18                 ++dp;
19                 ++end;
20         }
21         while (str[end] != '\0')
22                 ++end;
23                 
24         ParanoidNumber m(1);
25         for (int i = dp-1; i >= 0; --i)
26         {
27                 ParanoidNumber b(str[i]-'0');
28                 b*=m;
29                 this->operator+=(b);
30                 m*=10;
31         }
32         ParanoidNumber n(1);
33         for (int i = dp+1; i < end; ++i)
34         {
35                 n/=10;
36                 ParanoidNumber b(str[i]-'0');
37                 b*=n;
38                 this->operator+=(b);
39         }
40         
41 }
42
43 ParanoidNumber * ParanoidNumber::InsertAfter(float value, Optype op)
44 {
45         return InsertAfter(new ParanoidNumber(value, op));
46 }
47         
48 ParanoidNumber * ParanoidNumber::InsertAfter(ParanoidNumber * insert)
49 {
50         //Debug("Insert {%s} after {%f, %s}",insert->Str().c_str(),
51         //      m_value, g_opstr[m_op]);
52         ParanoidNumber * n = m_next;
53         m_next = insert;
54         
55         ParanoidNumber * p = m_next;
56         while (p->m_next != NULL)
57                 p = p->m_next;
58         p->m_next = n;
59         
60         return m_next;
61 }
62
63
64 ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a)
65 {
66         const ParanoidNumber * na = &a;
67         ParanoidNumber * nb = this;
68         ParanoidNumber * p = NULL;
69         while (na != NULL && nb != NULL)
70         {
71                 nb->m_value = na->m_value;
72                 nb->m_op = na->m_op;
73                 na = na->m_next;
74                 p = nb;
75                 nb = nb->m_next;
76                 
77         }       
78         
79         while (na != NULL) // => nb == NULL
80         {
81                 InsertAfter(na->m_value, na->m_op);
82                 na = na->m_next;
83         }
84
85         if (nb != NULL)
86         {
87                 if (p != NULL)
88                         p->m_next = NULL;
89                 delete nb;
90         }
91         return *this;
92 }
93
94 ParanoidNumber & ParanoidNumber::operator+=(const ParanoidNumber & a)
95 {
96         ParanoidNumber * insert = new ParanoidNumber(a, ADD);
97         if (m_next == NULL || m_next->m_op == ADD || m_next->m_op == SUBTRACT)
98         {
99                 InsertAfter(insert);
100                 Simplify();
101                 return *this;
102         }
103         
104         if (m_next->m_op == MULTIPLY) // (a*b) + c == (a+[c/b]) * b
105                 insert->operator/=(*m_next);
106         else
107                 insert->operator*=(*m_next); // (a/b) + c == (a+[c*b])/b
108         
109         if (insert->m_next != NULL) // neither of the above simplified
110         {
111                 //Debug("{%s} did not simplify, change back to {%s}", insert->Str().c_str(), a.Str().c_str());
112                 insert->operator=(a); // Just add as is
113                 insert->m_op = ADD;
114                 ParanoidNumber * n = this;
115                 while (n->m_next != NULL)
116                         n = n->m_next;
117                 n->InsertAfter(insert);
118         }
119         else
120         {
121                 InsertAfter(insert);
122         }
123         Simplify();
124         return *this;
125 }
126 ParanoidNumber & ParanoidNumber::operator-=(const ParanoidNumber & a)
127 {
128         ParanoidNumber * insert = new ParanoidNumber(a, SUBTRACT);
129         if (m_next == NULL || m_next->m_op == ADD || m_next->m_op == SUBTRACT)
130         {
131                 InsertAfter(insert);
132                 Simplify();
133                 return *this;
134         }
135         
136         if (m_next->m_op == MULTIPLY) // (a*b) - c == (a-[c/b]) * b
137                 insert->operator/=(*m_next);
138         else
139                 insert->operator*=(*m_next); // (a/b) - c == (a-[c*b])/b
140         
141         if (insert->m_next != NULL) // neither of the above simplified
142         {
143                 //Debug("{%s} did not simplify, change back to {%s}", insert->Str().c_str(), a.Str().c_str());
144                 insert->operator=(a); // Just add as is
145                 insert->m_op = SUBTRACT;
146                 ParanoidNumber * n = this;
147                 while (n->m_next != NULL)
148                         n = n->m_next;
149                 n->InsertAfter(insert);
150         }       
151         else
152         {
153                 InsertAfter(insert);
154         }
155         Simplify();
156         return *this;
157 }
158
159 ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a)
160 {
161         ParanoidNumber * n = m_next;
162         while (n != NULL)
163         {
164                 if (n->m_op == ADD || n->m_op == SUBTRACT)
165                 {
166                         n->operator*=(a);
167                         break;
168                 }
169                 n = n->m_next;
170         }
171                 
172         InsertAfter(new ParanoidNumber(a, MULTIPLY));
173         Simplify();
174         return *this;
175 }
176
177
178 ParanoidNumber & ParanoidNumber::operator/=(const ParanoidNumber & a)
179 {
180         ParanoidNumber * n = m_next;
181         while (n != NULL)
182         {
183                 if (n->m_op == ADD || n->m_op == SUBTRACT)
184                 {
185                         n->operator/=(a);
186                         break;
187                 }
188                 n = n->m_next;
189         }
190                 
191         InsertAfter(new ParanoidNumber(a, DIVIDE));
192         Simplify();
193         return *this;
194 }
195
196 double ParanoidNumber::ToDouble() const
197 {
198         double value = (m_op == SUBTRACT) ? -m_value : m_value;
199         const ParanoidNumber * n = m_next;
200         while (n != NULL)
201         {
202                 switch (n->m_op)
203                 {
204                         case ADD:
205                         case SUBTRACT:
206                                 return value + n->ToDouble();
207                                 break;
208                         case MULTIPLY:
209                                 value *= n->m_value;
210                                 break;
211                         case DIVIDE:
212                                 value /= n->m_value;
213                                 break;
214                 }
215                 n = n->m_next;
216         }
217         return value;
218 }
219
220 void ParanoidNumber::Simplify()
221 {
222         ParanoidNumber * n = m_next;
223         ParanoidNumber * p = this;
224         
225         while (n != NULL)
226         {
227                 
228                 float a = p->m_value;
229                 switch (n->m_op)
230                 {
231                         case ADD:
232                                 n->Simplify();
233                                 feclearexcept(FE_ALL_EXCEPT);
234                                 a += n->m_value;
235                                 break;
236                         case SUBTRACT:
237                                 n->Simplify();
238                                 feclearexcept(FE_ALL_EXCEPT);
239                                 a -= n->m_value;
240                                 break;
241                         case MULTIPLY:
242                                 feclearexcept(FE_ALL_EXCEPT);
243                                 a *= n->m_value;
244                                 break;
245                         case DIVIDE:
246                                 feclearexcept(FE_ALL_EXCEPT);
247                                 a /= n->m_value;
248                                 break;
249                                 
250                 }
251                 // can't merge p and n
252                 if (fetestexcept(FE_ALL_EXCEPT))
253                 {
254                         while (n != NULL && n->m_op != ADD && n->m_op != SUBTRACT)
255                                 n = n->m_next;
256                         if (n != NULL)
257                                 n->Simplify();
258                         return;
259                 }
260                 else
261                 {
262                         //  merge n into p
263                         p->m_value = a;
264                         p->m_next = n->m_next;
265                         n->m_next = NULL;
266                         delete n;
267                         n = p->m_next;          
268                 }
269                 //Debug("  -> {%s}", Str().c_str());
270         }
271 }
272
273 string ParanoidNumber::Str() const
274 {
275         string result("");
276         switch (m_op)
277         {
278                 case ADD:
279                         result += " +";
280                         break;
281                 case SUBTRACT:
282                         result += " -";
283                         break;
284                 case MULTIPLY:
285                         result += " *";
286                         break;
287                 case DIVIDE:
288                         result += " /";
289                         break;
290         }
291         stringstream s("");
292         s << m_value;
293         result += s.str();
294         if (m_next != NULL)
295                 result += m_next->Str();
296         return result;
297 }
298
299 }

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