| [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 | 
 | 
|---|
 | 10 | namespace 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 
 | 
|---|
| [2804] | 17 |   like syntax. Spaces 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
 | 
|---|
| [2804] | 25 |   are referred to as <tt> x y z </tt>. \n
 | 
|---|
| [2598] | 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] | 66 | RPNExpressionEvaluator::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] | 86 | RPNExpressionEvaluator::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 | 
 | 
|---|
 | 99 | RPNExpressionEvaluator::~RPNExpressionEvaluator()
 | 
|---|
 | 100 | {
 | 
|---|
 | 101 | }
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 | /* Operations sur le stack RPN */
 | 
|---|
 | 104 | /* --Methode-- */
 | 
|---|
| [2598] | 105 | //! Return the stack top (x) 
 | 
|---|
| [2510] | 106 | double 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-- */
 | 
|---|
 | 115 | int 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") { 
 | 
|---|
| [3617] | 240 |       double rnd = GaussianRand(1.,0.);
 | 
|---|
| [2510] | 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;
 | 
|---|
| [2913] | 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 |         }
 | 
|---|
| [2510] | 259 |       }
 | 
|---|
 | 260 |     }
 | 
|---|
 | 261 |     else if (args[k] == "product") { 
 | 
|---|
 | 262 |       double px;
 | 
|---|
 | 263 |       int nn = ProductStack( px);
 | 
|---|
| [2512] | 264 |       if (nn == 0) return k;
 | 
|---|
| [2510] | 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") {
 | 
|---|
| [2512] | 272 |       if ( CheckStack( x, y) ) return k;
 | 
|---|
| [2510] | 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) {
 | 
|---|
| [2512] | 287 |       if (esptr == args[k].c_str()) return k; 
 | 
|---|
| [2510] | 288 |       rpnstack_.push(x);
 | 
|---|
 | 289 |     }
 | 
|---|
 | 290 | 
 | 
|---|
 | 291 |   }
 | 
|---|
| [2512] | 292 |   return(args.size()+1);
 | 
|---|
| [2510] | 293 | }
 | 
|---|
 | 294 | 
 | 
|---|
 | 295 | inline 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 | 
 | 
|---|
 | 316 | int 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 | 
 | 
|---|
 | 329 | int 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
 | 
|---|