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

Last change on this file since 3857 was 3617, checked in by cmv, 16 years ago

chgt nom Gaussian -> GaussianRand etc.. pour ambiguite, cmv 02/05/2009

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