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

Last change on this file since 2779 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

File size: 9.3 KB
RevLine 
[2615]1#include "sopnamsp.h"
[2510]2#include "rpneval.h"
3#include <stdlib.h>
[2532]4#include <stdio.h>
[2510]5#include "strutilxx.h"
6#include "srandgen.h"
7#include <iostream>
8#include <math.h>
9
10namespace SOPHYA {
11
12/*!
[2598]13 \class RPNExpressionEvaluator
[2510]14 \ingroup SysTools
15 Arithmetic expression (double precision float) evaluator
16 in Reverse Polish Notation (RPN). This is an HP calculator
17 like syntax. Space are used for separating the string
[2598]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 x </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
[2510]59*/
60
[2598]61/*!
62 \brief Parses the string \b sex into words and perform the specified operations on the stack.
63
64 Can throw RPNExprException
65*/
[2510]66RPNExpressionEvaluator::RPNExpressionEvaluator(string const & sex)
67{
68 vector<string> exe;
69 FillVStringFrString(sex, exe, ' ');
70 int rc = EvalRPNExpr(exe, 0);
[2512]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 }
[2510]79}
80
[2598]81/*!
82 \brief Perform the operations specified by \b on the stack, starting from element \b exe[off].
83
84 Can throw RPNExprException
85*/
[2510]86RPNExpressionEvaluator::RPNExpressionEvaluator(vector<string> & exe, int off)
87{
88 int rc = EvalRPNExpr(exe, off);
[2512]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 }
[2510]97}
98
99RPNExpressionEvaluator::~RPNExpressionEvaluator()
100{
101}
102
103/* Operations sur le stack RPN */
104/* --Methode-- */
[2598]105//! Return the stack top (x)
[2510]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
[2512]118 if (args.size() <= off) return 1;
[2510]119 double x,y;
120 x = y = 0.;
[2512]121
[2510]122 for(int k=off; k<args.size(); k++) {
123 // Les 4 operations de base + - * /
124 if (args[k] == "+") {
[2512]125 if ( CheckStack( x, y) ) return k;
[2510]126 rpnstack_.top() = y+x;
127 }
128 else if (args[k] == "-") {
[2512]129 if ( CheckStack( x, y) ) return k;
[2510]130 rpnstack_.top() = y-x;
131 }
132 else if (args[k] == "*") {
[2512]133 if ( CheckStack( x, y) ) return k;
[2510]134 rpnstack_.top() = y*x;
135 }
136 else if (args[k] == "/") {
[2512]137 if ( CheckStack( x, y) ) return k;
[2510]138 rpnstack_.top() = y/x;
139 }
140 else if (args[k] == "%") {
[2512]141 if ( CheckStack( x, y) ) return k;
[2510]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") {
[2512]153 if ( CheckStack( x) ) return k;
[2510]154 rpnstack_.top() = cos(x);
155 }
156 else if (args[k] == "sin") {
[2512]157 if ( CheckStack( x) ) return k;
[2510]158 rpnstack_.top() = sin(x);
159 }
160 else if (args[k] == "tan") {
[2512]161 if ( CheckStack( x) ) return k;
[2510]162 rpnstack_.top() = tan(x);
163 }
164 else if (args[k] == "acos") {
[2512]165 if ( CheckStack( x) ) return k;
[2510]166 rpnstack_.top() = acos(x);
167 }
168 else if (args[k] == "asin") {
[2512]169 if ( CheckStack( x) ) return k;
[2510]170 rpnstack_.top() = asin(x);
171 }
172 else if (args[k] == "atan") {
[2512]173 if ( CheckStack( x) ) return k;
[2510]174 rpnstack_.top() = atan(x);
175 }
176 else if (args[k] == "chs") {
[2512]177 if ( CheckStack( x) ) return k;
[2510]178 rpnstack_.top() = -x;
179 }
180 else if (args[k] == "sqrt") {
[2512]181 if ( CheckStack( x) ) return k;
[2510]182 rpnstack_.top() = sqrt(x);
183 }
184 else if (args[k] == "sq") { // x^2
[2512]185 if ( CheckStack( x) ) return k;
[2510]186 rpnstack_.top() = x*x;
187 }
188 else if (args[k] == "log") {
[2512]189 if ( CheckStack( x) ) return k;
[2510]190 rpnstack_.top() = log(x);
191 }
192 else if (args[k] == "log10") {
[2512]193 if ( CheckStack( x) ) return k;
[2510]194 rpnstack_.top() = log10(x);
195 }
196 else if (args[k] == "exp") {
[2512]197 if ( CheckStack( x) ) return k;
[2510]198 rpnstack_.top() = exp(x);
199 }
200 else if (args[k] == "fabs") {
[2512]201 if ( CheckStack( x) ) return k;
[2510]202 rpnstack_.top() = fabs(x);
203 }
204 else if (args[k] == "floor") {
[2512]205 if ( CheckStack( x) ) return k;
[2510]206 rpnstack_.top() = floor(x);
207 }
208 else if (args[k] == "ceil") {
[2512]209 if ( CheckStack( x) ) return k;
[2510]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") {
[2512]214 if ( CheckStack( x) ) return k;
[2510]215 rpnstack_.top() = x*M_PI/180.;
216 }
217 else if (args[k] == "rad2deg") {
[2512]218 if ( CheckStack( x) ) return k;
[2510]219 rpnstack_.top() = x*180./M_PI;
220 }
221 // Les fonctions usuelles a 2 argument f(x,y)
222 else if (args[k] == "pow") {
[2512]223 if ( CheckStack( x, y) ) return k;
[2510]224 rpnstack_.top() = pow(y,x);
225 }
226 else if (args[k] == "atan2") {
[2512]227 if ( CheckStack( x, y) ) return k;
[2510]228 rpnstack_.top() = atan2(x,y);
229 }
230 // generateur aleatoire
[2596]231 else if (args[k] == "rand01") {
[2510]232 double rnd = drand01();
233 rpnstack_.push(rnd);
234 }
[2596]235 else if (args[k] == "randpm1") {
236 double rnd = drandpm1();
237 rpnstack_.push(rnd);
238 }
239 else if (args[k] == "gaurand") {
[2510]240 double rnd = GauRnd(0., 1.);
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 if ((args[k] == "sigma") || (args[k] == "sigmean"))
253 rpnstack_.push(sqrt(sx2/fnn-(x*x/(fnn*fnn))));
254 else if ((args[k] == "mean") || (args[k] == "sigmean")) rpnstack_.push(sx/fnn);
255 else rpnstack_.push(sx2/fnn-(x*x/(fnn*fnn)));
256 }
257 }
258 else if (args[k] == "product") {
259 double px;
260 int nn = ProductStack( px);
[2512]261 if (nn == 0) return k;
[2510]262 rpnstack_.push(px);
263 }
264 // Fonctions de manipulation de stack
265 else if (args[k] == "print") {
266 PrintStack();
267 }
268 else if (args[k] == "x<>y") {
[2512]269 if ( CheckStack( x, y) ) return k;
[2510]270 rpnstack_.top() = x; rpnstack_.push(y);
271 }
272 else if (args[k] == "pop") {
273 rpnstack_.pop();
274 }
275 else if (args[k] == "push") {
276 if (rpnstack_.empty()) rpnstack_.push(0.);
277 else rpnstack_.push(rpnstack_.top());
278 }
279 // On met un nombre sur le stack
280 else {
281 char * esptr;
282 x = strtod(args[k].c_str(), &esptr);
283 // if (ctof(args[k].c_str(),&x) < 0) {
[2512]284 if (esptr == args[k].c_str()) return k;
[2510]285 rpnstack_.push(x);
286 }
287
288 }
[2512]289 return(args.size()+1);
[2510]290}
291
292inline void RPNExpressionEvaluator::PrintStack()
293{
294 if (rpnstack_.empty())
295 cout << "RPNExpressionEvaluator::PrintStack() Empty stack " << endl;
296 else {
297 stack<double> s;
298 s = rpnstack_;
299 int k = 0;
300 cout << "RPNExpressionEvaluator::PrintStack() Size()= " << s.size() << endl;
301 while( !s.empty() ) {
302 cout << " " << k << ": " << s.top() << " ";
303 if (k == 0) cout << " (x) " << endl;
304 else if (k == 1) cout << " (y) " << endl;
305 else if (k == 2) cout << " (z) " << endl;
306 else cout << endl;
307 s.pop(); k++;
308 }
309 }
310
311}
312
313int RPNExpressionEvaluator::SumStack(double& sx, double& sx2)
314{
315 sx = sx2 = 0.;
316 int nn = 0;
317 double x = 0.;
318 while( !rpnstack_.empty() ) {
319 x = rpnstack_.top(); rpnstack_.pop();
320 sx += x; sx2 += x*x;
321 nn++;
322 }
323 return(nn);
324}
325
326int RPNExpressionEvaluator::ProductStack(double& px)
327{
328 px = 1.;
329 int nn = 0;
330 double x = 0.;
331 while( !rpnstack_.empty() ) {
332 x = rpnstack_.top(); rpnstack_.pop();
333 px *= x; nn++;
334 }
335 return(nn);
336}
337
338
339} // End of namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.