source: Sophya/trunk/SophyaLib/SysTools/rpneval.cc@ 2598

Last change on this file since 2598 was 2598, checked in by ansari, 21 years ago

Documentation (ajoutee ou completee) pour les classes du module SysTools - Reza 11 Aout 2004

File size: 9.3 KB
Line 
1#include "rpneval.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include "strutilxx.h"
5#include "srandgen.h"
6#include <iostream>
7#include <math.h>
8
9namespace SOPHYA {
10
11/*!
12 \class RPNExpressionEvaluator
13 \ingroup SysTools
14 Arithmetic expression (double precision float) evaluator
15 in Reverse Polish Notation (RPN). This is an HP calculator
16 like syntax. Space are used for separating the string
17 expression into tokens. \n
18 The string parsed by RPNExpressionEvaluator should be
19 formed by a set of space separated words. Each word may be
20 a numerical constant or operation or function.
21 All numeriacl constants are pushed to stack top.
22 The stack is limited only
23 by the available memory. The three numbers on the stack top
24 are referred to as <tt> x y x </tt>. \n
25 Available operations:
26 - op= + - * / % : replace (x,y) by x.op.y
27 - e pi : M_PI , M_E numerical constants
28 - f= sin cos tan asin acos atan : replace x by f(x)
29 - f= chs sqrt sq : (x<-f(x)) change-sign , square root and square (x<-x^2) operations
30 - f= log log10 exp : replace x by f(x)
31 - f= fabs floor ceiling : replace x by f(x)
32 - f= deg2rad rad2deg : replace x by f(x)
33 - f= rand01 randpm1 gaurand : pushes a random number on the stack top ([0 1] [-1 1] Gaussian)
34 - print x<>y pop push : stack operations
35 - sum product : Replace the complete stack by the sum / product of the numbers in the stack
36 - mean sigma : Replace the complete stack by the mean / sigma of the numbers in the stack
37
38 \sa CExpressionEvaluator Commander
39
40 The following output is produced by the sample code below:
41 \code
42 #include "rpneval.h"
43 ...
44 RPNExpressionEvaluator rpn1("4 2 print + 3 * ");
45 cout << "RPN1: 4 2 + 3 * -> rpn1.Value() = " << rpn1.Value() << endl;
46 RPNExpressionEvaluator rpn2("1 2 3 4 5 sum");
47 cout << "RPN2: 1 2 3 4 5 sum -> rpn2.Value() = " << rpn2.Value() << endl;
48 \endcode
49
50 Output:
51 \verbatim
52 RPNExpressionEvaluator::PrintStack() Size()= 2
53 0: 2 (x)
54 1: 4 (y)
55 RPN1: 4 2 + 3 * -> rpn1.Value() = 18
56 RPN2: 1 2 3 4 5 sum -> rpn2.Value() = 15
57 \endverbatim
58*/
59
60/*!
61 \brief Parses the string \b sex into words and perform the specified operations on the stack.
62
63 Can throw RPNExprException
64*/
65RPNExpressionEvaluator::RPNExpressionEvaluator(string const & sex)
66{
67 vector<string> exe;
68 FillVStringFrString(sex, exe, ' ');
69 int rc = EvalRPNExpr(exe, 0);
70 if (rc < exe.size()) {
71 string msg = "RPNExpressionEvaluator() - syntax error near ";
72 msg += exe[rc];
73 char buff[32];
74 sprintf(buff," (word %d)",rc);
75 msg += buff;
76 throw RPNExprException(msg);
77 }
78}
79
80/*!
81 \brief Perform the operations specified by \b on the stack, starting from element \b exe[off].
82
83 Can throw RPNExprException
84*/
85RPNExpressionEvaluator::RPNExpressionEvaluator(vector<string> & exe, int off)
86{
87 int rc = EvalRPNExpr(exe, off);
88 if (rc < exe.size()) {
89 string msg = "RPNExpressionEvaluator() - syntax error near ";
90 msg += exe[rc];
91 char buff[32];
92 sprintf(buff," (word %d)",rc);
93 msg += buff;
94 throw RPNExprException(msg);
95 }
96}
97
98RPNExpressionEvaluator::~RPNExpressionEvaluator()
99{
100}
101
102/* Operations sur le stack RPN */
103/* --Methode-- */
104//! Return the stack top (x)
105double RPNExpressionEvaluator::Evaluate() const
106{
107 double x;
108 if ( CheckStack( x) )
109 throw RPNExprException("RPNExpressionEvaluator::Evaluate() EmptyStack");
110 else return x;
111}
112
113/* --Methode-- */
114int RPNExpressionEvaluator::EvalRPNExpr(vector<string> & args, int off)
115{
116
117 if (args.size() <= off) return 1;
118 double x,y;
119 x = y = 0.;
120
121 for(int k=off; k<args.size(); k++) {
122 // Les 4 operations de base + - * /
123 if (args[k] == "+") {
124 if ( CheckStack( x, y) ) return k;
125 rpnstack_.top() = y+x;
126 }
127 else if (args[k] == "-") {
128 if ( CheckStack( x, y) ) return k;
129 rpnstack_.top() = y-x;
130 }
131 else if (args[k] == "*") {
132 if ( CheckStack( x, y) ) return k;
133 rpnstack_.top() = y*x;
134 }
135 else if (args[k] == "/") {
136 if ( CheckStack( x, y) ) return k;
137 rpnstack_.top() = y/x;
138 }
139 else if (args[k] == "%") {
140 if ( CheckStack( x, y) ) return k;
141 rpnstack_.top() = (int)y % (int)x;
142 }
143 // Les constantes : e , pi
144 else if (args[k] == "e") {
145 rpnstack_.push(M_E);
146 }
147 else if (args[k] == "pi") {
148 rpnstack_.push(M_PI);
149 }
150 // Les fonctions usuelles a 1 argument f(x)
151 else if (args[k] == "cos") {
152 if ( CheckStack( x) ) return k;
153 rpnstack_.top() = cos(x);
154 }
155 else if (args[k] == "sin") {
156 if ( CheckStack( x) ) return k;
157 rpnstack_.top() = sin(x);
158 }
159 else if (args[k] == "tan") {
160 if ( CheckStack( x) ) return k;
161 rpnstack_.top() = tan(x);
162 }
163 else if (args[k] == "acos") {
164 if ( CheckStack( x) ) return k;
165 rpnstack_.top() = acos(x);
166 }
167 else if (args[k] == "asin") {
168 if ( CheckStack( x) ) return k;
169 rpnstack_.top() = asin(x);
170 }
171 else if (args[k] == "atan") {
172 if ( CheckStack( x) ) return k;
173 rpnstack_.top() = atan(x);
174 }
175 else if (args[k] == "chs") {
176 if ( CheckStack( x) ) return k;
177 rpnstack_.top() = -x;
178 }
179 else if (args[k] == "sqrt") {
180 if ( CheckStack( x) ) return k;
181 rpnstack_.top() = sqrt(x);
182 }
183 else if (args[k] == "sq") { // x^2
184 if ( CheckStack( x) ) return k;
185 rpnstack_.top() = x*x;
186 }
187 else if (args[k] == "log") {
188 if ( CheckStack( x) ) return k;
189 rpnstack_.top() = log(x);
190 }
191 else if (args[k] == "log10") {
192 if ( CheckStack( x) ) return k;
193 rpnstack_.top() = log10(x);
194 }
195 else if (args[k] == "exp") {
196 if ( CheckStack( x) ) return k;
197 rpnstack_.top() = exp(x);
198 }
199 else if (args[k] == "fabs") {
200 if ( CheckStack( x) ) return k;
201 rpnstack_.top() = fabs(x);
202 }
203 else if (args[k] == "floor") {
204 if ( CheckStack( x) ) return k;
205 rpnstack_.top() = floor(x);
206 }
207 else if (args[k] == "ceil") {
208 if ( CheckStack( x) ) return k;
209 rpnstack_.top() = ceil(x);
210 }
211 // trunc et nint vire - ca ne compile pas sous linux - Reza 01/2003
212 else if (args[k] == "deg2rad") {
213 if ( CheckStack( x) ) return k;
214 rpnstack_.top() = x*M_PI/180.;
215 }
216 else if (args[k] == "rad2deg") {
217 if ( CheckStack( x) ) return k;
218 rpnstack_.top() = x*180./M_PI;
219 }
220 // Les fonctions usuelles a 2 argument f(x,y)
221 else if (args[k] == "pow") {
222 if ( CheckStack( x, y) ) return k;
223 rpnstack_.top() = pow(y,x);
224 }
225 else if (args[k] == "atan2") {
226 if ( CheckStack( x, y) ) return k;
227 rpnstack_.top() = atan2(x,y);
228 }
229 // generateur aleatoire
230 else if (args[k] == "rand01") {
231 double rnd = drand01();
232 rpnstack_.push(rnd);
233 }
234 else if (args[k] == "randpm1") {
235 double rnd = drandpm1();
236 rpnstack_.push(rnd);
237 }
238 else if (args[k] == "gaurand") {
239 double rnd = GauRnd(0., 1.);
240 rpnstack_.push(rnd);
241 }
242 // Fonction a N arguments - Somme, produit, etc ...
243 else if ((args[k] == "sum") || (args[k] == "mean") || (args[k] == "sigmean") ||
244 (args[k] == "sigma") || (args[k] == "sigma2") ) {
245 double sx, sx2;
246 int nn = SumStack( sx, sx2);
247 if (args[k] == "sum") rpnstack_.push(sx);
248 else {
249 if (nn == 0) return 1;
250 double fnn = nn;
251 if ((args[k] == "sigma") || (args[k] == "sigmean"))
252 rpnstack_.push(sqrt(sx2/fnn-(x*x/(fnn*fnn))));
253 else if ((args[k] == "mean") || (args[k] == "sigmean")) rpnstack_.push(sx/fnn);
254 else rpnstack_.push(sx2/fnn-(x*x/(fnn*fnn)));
255 }
256 }
257 else if (args[k] == "product") {
258 double px;
259 int nn = ProductStack( px);
260 if (nn == 0) return k;
261 rpnstack_.push(px);
262 }
263 // Fonctions de manipulation de stack
264 else if (args[k] == "print") {
265 PrintStack();
266 }
267 else if (args[k] == "x<>y") {
268 if ( CheckStack( x, y) ) return k;
269 rpnstack_.top() = x; rpnstack_.push(y);
270 }
271 else if (args[k] == "pop") {
272 rpnstack_.pop();
273 }
274 else if (args[k] == "push") {
275 if (rpnstack_.empty()) rpnstack_.push(0.);
276 else rpnstack_.push(rpnstack_.top());
277 }
278 // On met un nombre sur le stack
279 else {
280 char * esptr;
281 x = strtod(args[k].c_str(), &esptr);
282 // if (ctof(args[k].c_str(),&x) < 0) {
283 if (esptr == args[k].c_str()) return k;
284 rpnstack_.push(x);
285 }
286
287 }
288 return(args.size()+1);
289}
290
291inline void RPNExpressionEvaluator::PrintStack()
292{
293 if (rpnstack_.empty())
294 cout << "RPNExpressionEvaluator::PrintStack() Empty stack " << endl;
295 else {
296 stack<double> s;
297 s = rpnstack_;
298 int k = 0;
299 cout << "RPNExpressionEvaluator::PrintStack() Size()= " << s.size() << endl;
300 while( !s.empty() ) {
301 cout << " " << k << ": " << s.top() << " ";
302 if (k == 0) cout << " (x) " << endl;
303 else if (k == 1) cout << " (y) " << endl;
304 else if (k == 2) cout << " (z) " << endl;
305 else cout << endl;
306 s.pop(); k++;
307 }
308 }
309
310}
311
312int RPNExpressionEvaluator::SumStack(double& sx, double& sx2)
313{
314 sx = sx2 = 0.;
315 int nn = 0;
316 double x = 0.;
317 while( !rpnstack_.empty() ) {
318 x = rpnstack_.top(); rpnstack_.pop();
319 sx += x; sx2 += x*x;
320 nn++;
321 }
322 return(nn);
323}
324
325int RPNExpressionEvaluator::ProductStack(double& px)
326{
327 px = 1.;
328 int nn = 0;
329 double x = 0.;
330 while( !rpnstack_.empty() ) {
331 x = rpnstack_.top(); rpnstack_.pop();
332 px *= x; nn++;
333 }
334 return(nn);
335}
336
337
338} // End of namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.