ROOT  6.06/09
Reference Guide
TFormula_v5.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Nicolas Brun 19/08/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <math.h>
13 
14 #include "Riostream.h"
15 #include "TROOT.h"
16 #include "TClass.h"
17 #include "v5/TFormula.h"
18 #include "TMath.h"
19 #include "TRandom.h"
20 #include "TFunction.h"
21 #include "TMethodCall.h"
22 #include "TObjString.h"
23 #include "TError.h"
24 #include "v5/TFormulaPrimitive.h"
25 #include "TInterpreter.h"
26 #include "TVirtualMutex.h"
27 
28 #ifdef WIN32
29 #pragma optimize("",off)
30 #endif
31 
32 static Int_t gMAXOP=1000,gMAXPAR=1000,gMAXCONST=1000;
35 
37 
38 namespace ROOT {
39 
40  namespace v5 {
41 
42 //______________________________________________________________________________
43 // The FORMULA class (ROOT version 5)
44 //
45 //Begin_Html
46 /*
47 <img src="gif/tformula_classtree.gif">
48 */
49 //End_Html
50 //
51 // Example of valid expressions:
52 // - sin(x)/x
53 // - [0]*sin(x) + [1]*exp(-[2]*x)
54 // - x + y**2
55 // - x^2 + y^2
56 // - [0]*pow([1],4)
57 // - 2*pi*sqrt(x/y)
58 // - gaus(0)*expo(3) + ypol3(5)*x
59 // - gausn(0)*expo(3) + ypol3(5)*x
60 //
61 // In the last example above:
62 // gaus(0) is a substitute for [0]*exp(-0.5*((x-[1])/[2])**2)
63 // and (0) means start numbering parameters at 0
64 // gausn(0) is a substitute for [0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))
65 // and (0) means start numbering parameters at 0
66 // expo(3) is a substitute for exp([3]+[4]*x)
67 // pol3(5) is a substitute for par[5]+par[6]*x+par[7]*x**2+par[8]*x**3
68 // (here Pol3 stands for Polynomial of degree 3)
69 //
70 // TMath functions can be part of the expression, eg:
71 // - TMath::Landau(x)*sin(x)
72 // - TMath::Erf(x)
73 //
74 // Comparisons operators are also supported (&&, ||, ==, <=, >=, !)
75 // Examples:
76 // sin(x*(x<0.5 || x>1))
77 // If the result of a comparison is TRUE, the result is 1, otherwise 0.
78 //
79 // Already predefined names can be given. For example, if the formula
80 // TFormula old(sin(x*(x<0.5 || x>1))) one can assign a name to the formula. By default
81 // the name of the object = title = formula itself.
82 // old.SetName("old").
83 // then, old can be reused in a new expression.
84 // TFormula new("x*old") is equivalent to:
85 // TFormula new("x*sin(x*(x<0.5 || x>1))")
86 //
87 // Up to 4 dimensions are supported (indicated by x, y, z, t)
88 // An expression may have 0 parameters or a list of parameters
89 // indicated by the sequence [par_number]
90 //
91 // A graph showing the logic to compile and analyze a formula
92 // is shown in TFormula::Compile and TFormula::Analyze.
93 // Once a formula has been compiled, it can be evaluated for a given
94 // set of parameters. see graph in TFormula::EvalPar.
95 //
96 // This class is the base class for the function classes TF1,TF2 and TF3.
97 // It is also used by the ntuple selection mechanism TNtupleFormula.
98 //
99 // In version 7 of TFormula, the usage of fOper has been changed
100 // to improve the performance of TFormula::EvalPar.
101 // Conceptually, fOper was changed from a simple array of Int_t
102 // to an array of composite values.
103 // For example a 'ylandau(5)' operation used to be encoded as 4105;
104 // it is now encoded as (klandau >> kTFOperShit) + 5
105 // Any class inheriting from TFormula and using directly fOper (which
106 // is now a private data member), needs to be updated to take this
107 // in consideration. The member functions recommended to set and
108 // access fOper are: SetAction, GetAction, GetActionParam
109 // For more performant access to the information, see the implementation
110 // TFormula::EvalPar
111 //
112 // CHANGING DEFAULT SETTINGS
113 // =========================
114 // When creating complex formula , it may be necessary to increase
115 // some default parameters. see static function TFormula::SetMaxima
116 //
117 // WHY TFormula CANNOT ACCEPT A CLASS MEMBER FUNCTION ?
118 // ====================================================
119 // This is a frequently asked question.
120 // C++ is a strongly typed language. There is no way for TFormula (without
121 // recompiling this class) to know about all possible user defined data types.
122 // This also apply to the case of a static class function.
123 // Because TMath is a special and frequent case, TFormula is aware
124 // of all TMath functions.
125 
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 /// Formula default constructor.
129 
131 {
132  fNdim = 0;
133  fNpar = 0;
134  fNoper = 0;
135  fNconst = 0;
136  fNumber = 0;
137  fExpr = 0;
138  fOper = 0;
139  fConst = 0;
140  fParams = 0;
141  fNstring= 0;
142  fNames = 0;
143  fNval = 0;
144  //
145  //MI change
146  fNOperOptimized = 0;
147  fExprOptimized = 0;
148  fOperOptimized = 0;
149  fOperOffset = 0;
150  fPredefined = 0;
151  fOptimal = (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalParOld;
152 }
153 
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Normal Formula constructor.
157 
158 TFormula::TFormula(const char *name,const char *expression) :
159  TNamed(name,expression)
160 {
161  fNdim = 0;
162  fNpar = 0;
163  fNoper = 0;
164  fNconst = 0;
165  fNumber = 0;
166  fExpr = 0;
167  fOper = 0;
168  fConst = 0;
169  fParams = 0;
170  fNstring= 0;
171  fNames = 0;
172  fNval = 0;
173  //
174  //MI change
175  fNOperOptimized = 0;
176  fExprOptimized = 0;
177  fOperOptimized = 0;
178  fOperOffset = 0;
179  fPredefined = 0;
180  fOptimal = (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalParOld;
181 
182  if (!expression || !*expression) {
183  Error("TFormula", "expression may not be 0 or have 0 length");
184  return;
185  }
186 
187  //eliminate blanks in expression
188  Int_t i,j,nch;
189  nch = strlen(expression);
190  char *expr = new char[nch+1];
191  j = 0;
192  for (i=0;i<nch;i++) {
193  if (expression[i] == ' ') continue;
194  if (i > 0 && (expression[i] == '*') && (expression[i-1] == '*')) {
195  expr[j-1] = '^';
196  continue;
197  }
198  expr[j] = expression[i]; j++;
199  }
200  expr[j] = 0;
201  Bool_t gausNorm = kFALSE;
202  Bool_t landauNorm = kFALSE;
203  Bool_t linear = kFALSE;
204 
205  if (j) {
206  TString chaine = expr;
207  //special case for functions for linear fitting
208  if (chaine.Contains("++"))
209  linear = kTRUE;
210  // special case for normalized gaus
211  if (chaine.Contains("gausn")) {
212  gausNorm = kTRUE;
213  TString tmp = chaine;
214  tmp.ReplaceAll("gausn","");
215  tmp.ReplaceAll("landaun","");
216  if ( tmp.Contains("gaus") )
217  Warning("TFormula","Cannot use both gaus and gausn - gaus will be treated as gausn");
218  if ( tmp.Contains("landau") )
219  Warning("TFormula","Cannot use both gausn and landau - landau will be treated as landaun");
220  }
221  // special case for normalized landau
222  if (chaine.Contains("landaun")) {
223  landauNorm = kTRUE;
224  TString tmp = chaine;
225  tmp.ReplaceAll("landaun","");
226  tmp.ReplaceAll("gausn","");
227  if ( tmp.Contains("gaus") ) {
228  Warning("TFormula","Cannot use both gaus and landaun - gaus will be treated as gausn");
229  }
230  if ( tmp.Contains("landau") )
231  Warning("TFormula","Cannot use both landau and landaun - landau will be treated as landaun");
232  }
233  // need to the replacement here for the error message before
234  if (gausNorm)
235  chaine.ReplaceAll("gausn","gaus");
236  if (landauNorm)
237  chaine.ReplaceAll("landaun","landau");
238 
239  SetTitle(chaine.Data());
240  }
241  delete [] expr;
242 
243  if (linear) SetBit(kLinear);
244 
245  if (Compile()) return;
246 
247  if (gausNorm) SetBit(kNormalized);
248  if (landauNorm) SetBit(kNormalized);
249 
250  // Store formula in linked list of formula in ROOT
251 
252 
253  if (strcmp(name,"x")==0 || strcmp(name,"y")==0 ||
254  strcmp(name,"z")==0 || strcmp(name,"t")==0 )
255  {
256  Error("TFormula","The name \'%s\' is reserved as a TFormula variable name.\n"
257  "\tThis function will not be registered in the list of functions",name);
258  } else {
260  TFormula *old = (TFormula*)gROOT->GetListOfFunctions()->FindObject(name);
261  if (old) {
262  gROOT->GetListOfFunctions()->Remove(old);
263  }
264  gROOT->GetListOfFunctions()->Add(this);
265  }
266 }
267 
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Default constructor.
271 
272 TFormula::TFormula(const TFormula &formula) : TNamed()
273 {
274  fNdim = 0;
275  fNpar = 0;
276  fNoper = 0;
277  fNconst = 0;
278  fNumber = 0;
279  fExpr = 0;
280  fOper = 0;
281  fConst = 0;
282  fParams = 0;
283  fNstring= 0;
284  fNames = 0;
285  fNval = 0;
286  fNOperOptimized = 0;
287  fPredefined = 0;
288  fOperOffset = 0;
289  fExprOptimized = 0;
290  fOperOptimized = 0;
291 
292  ((TFormula&)formula).TFormula::Copy(*this);
293 }
294 
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 /// Operator =
298 
300 {
301  if (this != &rhs) {
302  rhs.Copy(*this);
303  }
304  return *this;
305 }
306 
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Formula default destructor.
310 
312 {
313  if (gROOT) {
315  gROOT->GetListOfFunctions()->Remove(this);
316  }
317 
318  ClearFormula();
319 }
320 
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Check if the chain as function call.
324 ///
325 /// If you overload this member function, you also HAVE TO
326 /// never call the constructor:
327 ///
328 /// TFormula::TFormula(const char *name,const char *expression)
329 ///
330 /// and write your own constructor
331 ///
332 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
333 ///
334 /// which has to call the TFormula default constructor and whose implementation
335 /// should be similar to the implementation of the normal TFormula constructor
336 ///
337 /// This is necessary because the normal TFormula constructor call indirectly
338 /// the virtual member functions Analyze, DefaultString, DefaultValue
339 /// and DefaultVariable.
340 
341 Bool_t TFormula::AnalyzeFunction(TString &chaine, Int_t &err, Int_t offset)
342 {
343  int i;
344 
345  // We have to decompose the chain is 3 potential components:
346  // namespace::functionName( args )
347 
348  Ssiz_t argStart = chaine.First('(');
349  if (argStart<0) return false;
350 
351  TString functionName = chaine(0,argStart);
352 
353  // This does not support template yet (where the scope operator might be in
354  // one of the template arguments
355  Ssiz_t scopeEnd = functionName.Last(':');
356  TString spaceName;
357  if (scopeEnd>0 && functionName[scopeEnd-1]==':') {
358  spaceName = functionName(0,scopeEnd-1);
359  functionName.Remove(0,scopeEnd+1);
360  }
361 
362  // Now we need to count and decompose the actual arguments, we could also check the type
363  // of the arguments
364  if (chaine[chaine.Length()-1] != ')') {
365  Error("AnalyzeFunction","We thought we had a function but we dont (in %s)\n",chaine.Data());
366  }
367 
368  TString args = chaine(argStart+1,chaine.Length()-2-argStart);
369  TObjArray argArr;
370  argArr.SetOwner(kTRUE);
371  //fprintf(stderr,"args are '%s'\n",args.Data());
372 
373  Bool_t inString = false;
374  int paran = 0;
375  int brack = 0;
376  int prevComma = 0;
377  int nargs = 0;
378  for(i=0; i<args.Length(); i++) {
379  if (args[i]=='"') inString = !inString;
380  if (inString) continue;
381 
382  Bool_t foundArg = false;
383  switch(args[i]) {
384 
385  case '(': paran++; break;
386  case ')': paran--; break;
387  case '[': brack++; break;
388  case ']': brack--; break;
389 
390  case ',': if (paran==0 && brack==0) { foundArg = true; } break;
391  }
392  if ((i+1)==args.Length()) {
393  foundArg = true; i++;
394  }
395  if (foundArg) {
396  TString arg = args(prevComma,i-prevComma);
397 
398  // Here we could
399  // a) check the type
400  //fprintf(stderr,"found #%d arg %s\n",nargs,arg.Data());
401 
402  // We register the arg for later usage
403  argArr.Add(new TObjString(arg));
404  nargs++;
405 
406  prevComma = i+1;
407  };
408  }
409 
410  if (nargs>999) {
411  err = 7;
412  return false;
413  }
414 
415  // Now we need to lookup the function and check its arguments.
416  TClass *ns = (spaceName.Length()) ? TClass::GetClass(spaceName) : 0;
417  ClassInfo_t *cinfo = 0;
418  if (ns) {
419  cinfo = ns->GetClassInfo();
420  } else {
421  cinfo = gInterpreter->ClassInfo_Factory();
422  }
423 
424  // ROOT does yet have a complete TType class, but TCling does,
425  // so let's use that for now.
426  static TypeInfo_t *const doubletype { gInterpreter->TypeInfo_Factory("double") };
427 
428  std::vector<TypeInfo_t*> proto(nargs,doubletype);
429 
430  CallFunc_t *callfunc = gInterpreter->CallFunc_Factory();
431  Long_t func_offset;
432  gInterpreter->CallFunc_SetFuncProto(callfunc,cinfo,functionName,proto,false,&func_offset,ROOT::kConversionMatch);
433 
434  TMethodCall *method = new TMethodCall(ns,callfunc,func_offset);
435 
436  if (!ns) gInterpreter->ClassInfo_Delete(cinfo);
437  gInterpreter->CallFunc_Delete(callfunc);
438 
439  if (method->IsValid()) {
440  if (method->ReturnType() == TMethodCall::kOther) {
441  /*
442  Error("Compile",
443  "TFormula can only call interpreted and compiled function that returns a numerical type %s returns a %s\n",
444  method->GetMethodName(), method->GetMethod()->GetReturnTypeName());
445  */
446  err=29;
447 
448  } else {
449 
450  // Analyze the arguments
451  TIter next(&argArr);
452  TObjString *objstr;
453  while ( (objstr=(TObjString*)next()) ) {
454  Analyze(objstr->String(),err,offset);
455  }
456 
457  fFunctions.Add(method);
458  fExpr[fNoper] = method->GetMethod()->GetPrototype();
459  SetAction(fNoper, kFunctionCall, fFunctions.GetLast()*1000 + nargs);
460  fNoper++;
461  return true;
462  }
463  }
464 
465  delete method;
466  //
467  // MI change - extended space of functions
468  // not forward compatible change
469  //
470  TString cbase(chaine);
471  Int_t args_paran = cbase.First("(");
472  if (args_paran>0){
473  cbase[args_paran]=0;
474  }
475 
476  ROOT::v5::TFormulaPrimitive *prim = ROOT::v5::TFormulaPrimitive::FindFormula(cbase, args_paran>0 ? cbase.Data() + args_paran + 1 : (const char*)0);
477  if (prim && (!IsA()->GetBaseClass("TTreeFormula"))) {
478  // TO BE DONE ALSO IN TTREFORMULA - temporary fix MI
479  // Analyze the arguments
480  TIter next(&argArr);
481  TObjString *objstr;
482  while ( (objstr=(TObjString*)next()) ) {
483  Analyze(objstr->String(),err,offset); if (err) return kFALSE;
484  }
485  if (nargs!=prim->fNArguments) {
486  Error("Compile", "%s requires %d arguments",
487  prim->GetName(), prim->fNArguments);
488  return kFALSE;
489  }
490  fExpr[fNoper] = prim->GetName();
491  if (prim->fType==10){
492  SetAction(fNoper, kFD1);
493  }
494  if (prim->fType==110){
495  SetAction(fNoper, kFD2);
496  }
497  if (prim->fType==1110){
498  SetAction(fNoper, kFD3);
499  }
500  if (prim->fType==-1){
501  SetAction(fNoper, kFDM);
502  if (fNpar<prim->fNParameters) fNpar+=prim->fNParameters;
503  }
504 
505  fNoper++;
506  return kTRUE;
507  }
508 
509  return kFALSE;
510 }
511 
512 
513 ////////////////////////////////////////////////////////////////////////////////
514 /// Analyze a sub-expression in one formula.
515 ///
516 /// Expressions in one formula are recursively analyzed.
517 /// Result of analysis is stored in the object tables.
518 ///
519 /// Table of function codes and errors
520 /// ==================================
521 ///
522 /// * functions :
523 ///
524 /// + 1 pow 20
525 /// - 2 sq 21
526 /// * 3 sqrt 22
527 /// / 4 strstr 23
528 /// % 5 min 24
529 /// max 25
530 /// log 30
531 /// cos 10 exp 31
532 /// sin 11 log10 32
533 /// tan 12
534 /// acos 13 abs 41
535 /// asin 14 sign 42
536 /// atan 15 int 43
537 /// atan2 16
538 /// fmod 17 rndm 50
539 ///
540 /// cosh 70 acosh 73
541 /// sinh 71 asinh 74
542 /// tanh 72 atanh 75
543 ///
544 /// expo 100 gaus 110 gausn (see note below)
545 /// expo(0) 100 0 gaus(0) 110 0 gausn(0)
546 /// expo(1) 100 1 gaus(1) 110 1 gausn(1)
547 /// xexpo 100 x xgaus 110 x xgausn
548 /// yexpo 101 x ygaus 111 x ygausn
549 /// zexpo 102 x zgaus 112 x zgausn
550 /// xyexpo 105 x xygaus 115 x xygausn
551 /// yexpo(5) 102 5 ygaus(5) 111 5 ygausn(5)
552 /// xyexpo(2) 105 2 xygaus(2) 115 2 xygausn(2)
553 ///
554 /// landau 120 x landaun (see note below)
555 /// landau(0) 120 0 landaun(0)
556 /// landau(1) 120 1 landaun(1)
557 /// xlandau 120 x xlandaun
558 /// ylandau 121 x ylandaun
559 /// zlandau 122 x zlandaun
560 /// xylandau 125 x xylandaun
561 /// ylandau(5) 121 5 ylandaun(5)
562 /// xylandau(2) 125 2 xylandaun(2)
563 ///
564 /// pol0 130 x pol1 130 1xx
565 /// pol0(0) 130 0 pol1(0) 130 100
566 /// pol0(1) 130 1 pol1(1) 130 101
567 /// xpol0 130 x xpol1 130 101
568 /// ypol0 131 x ypol1 131 101
569 /// zpol0 132 x zpol1 132 1xx
570 /// ypol0(5) 131 5 ypol1(5) 131 105
571 ///
572 /// pi 40
573 ///
574 /// && 60 < 64
575 /// || 61 > 65
576 /// == 62 <= 66
577 /// != 63 => 67
578 /// ! 68
579 /// ==(string) 76 & 78
580 /// !=(string) 77 | 79
581 /// <<(shift) 80 >>(shift) 81
582 /// ? : 82
583 ///
584 /// * constants (kConstants) :
585 ///
586 /// c0 141 1 c1 141 2 etc..
587 ///
588 /// * strings (kStringConst):
589 ///
590 /// sX 143 x
591 ///
592 /// * variables (kFormulaVar) :
593 ///
594 /// x 144 0 y 144 1 z 144 2 t 144 3
595 ///
596 /// * parameters :
597 ///
598 /// [1] 140 1
599 /// [2] 140 2
600 /// etc.
601 ///
602 /// Special cases for normalized gaussian or landau distributions
603 /// =============================================================
604 /// the expression "gaus" is a substitute for
605 /// [0]*exp(-0.5*((x-[1])/[2])**2)
606 /// to obtain a standard normalized gaussian, use "gausn" instead of "gaus"
607 /// the expression "gausn" is a substitute for
608 /// [0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))
609 /// WARNING: gaus and gausn are mutually exclusive in the same expression.
610 ///
611 /// In the same way the expression "landau" is a substitute for
612 /// [0]*TMath::Landau(x,[1],[2],kFALSE)
613 /// to obtain a standard normalized landau, use "landaun" instead of "landau"
614 /// the expression "landaun" is a substitute for
615 /// [0]*TMath::Landau(x,[1],[2],kTRUE)
616 /// WARNING: landau and landaun are mutually exclusive in the same expression.
617 ///
618 /// Boolean optimization (kBoolOptmize) :
619 /// =====================================
620 ///
621 /// Those pseudo operation are used to implement lazy evaluation of
622 /// && and ||. When the left hand of the expression if false
623 /// (respectively true), the evaluation of the right is entirely skipped
624 /// (since it would not change the value of the expreession).
625 ///
626 /// && 142 11 (one operation on right) 142 21 (2 operations on right)
627 /// || 142 12 (one operation on right) 142 22 (2 operations on right)
628 ///
629 /// * functions calls (kFunctionCall) :
630 ///
631 /// f0 145 0 f1 145 1 etc..
632 ///
633 /// Errors :
634 /// ========
635 ///
636 /// 1 : Division By Zero
637 /// 2 : Invalid Floating Point Operation
638 /// 4 : Empty String
639 /// 5 : invalid syntax
640 /// 6 : Too many operators
641 /// 7 : Too many parameters
642 /// 10 : z specified but not x and y
643 /// 11 : z and y specified but not x
644 /// 12 : y specified but not x
645 /// 13 : z and x specified but not y
646 /// 20 : non integer value for parameter number
647 /// 21 : atan2 requires two arguments
648 /// 22 : pow requires two arguments
649 /// 23 : degree of polynomial not specified
650 /// 24 : Degree of polynomial must be positive
651 /// 25 : Degree of polynomial must be less than 20
652 /// 26 : Unknown name
653 /// 27 : Too many constants in expression
654 /// 28 : strstr requires two arguments
655 /// 29 : interpreted or compiled function have to return a numerical type
656 /// 30 : Bad numerical expression
657 /// 31 : Part of the variable exist but some of it is not accessible or useable
658 /// 40 : '(' is expected
659 /// 41 : ')' is expected
660 /// 42 : '[' is expected
661 /// 43 : ']' is expected
662 ///Begin_Html
663 
664 void TFormula::Analyze(const char *schain, Int_t &err, Int_t offset)
665 {
666  /*
667  <img src="gif/analyze.gif">
668  */
669  //End_Html
670  //
671  // Special functions
672  // -----------------
673  // By default, the formula is assigned fNumber=0. However, the following
674  // formula built with simple functions are assigned fNumber:
675  // "gaus" 100 (or gausn)
676  // "xygaus" 110
677  // "expo" 200
678  // "polN" 300+N
679  // "landau" 400
680  // "xylandau" 410
681  // Note that expressions like gaus(0), expo(1) will force fNumber=0
682  //
683  // Warning when deriving a class from TFormula
684  // -------------------------------------------
685  // If you overload this member function, you also HAVE TO
686  // never call the constructor:
687  //
688  // TFormula::TFormula(const char *name,const char *expression)
689  //
690  // and write your own constructor
691  //
692  // MyClass::MyClass(const char *name,const char *expression) : TFormula()
693  //
694  // which has to call the TFormula default constructor and whose implementation
695  // should be similar to the implementation of the normal TFormula constructor
696  //
697  // This is necessary because the normal TFormula constructor call indirectly
698  // the virtual member functions Analyze, DefaultString, DefaultValue
699  // and DefaultVariable.
700 
701  Int_t valeur,find,n,i,j,k,lchain,nomb,virgule,inter,nest;
702  valeur=find=n=i=j=k=lchain=nomb=virgule=inter=nest = 0;
703  Int_t compt,compt2,compt3,compt4;
704  Bool_t inString;
705  Double_t vafConst;
706  ULong_t vafConst2;
707  Bool_t parenthese;
708  TString s,chaine_error,chaine1ST;
709  TString s1,s2,s3,ctemp;
710 
711  TString chaine = schain;
712  const TFormula *oldformula;
713  Int_t modulo,plus,puiss10,puiss10bis,moins,multi,divi,puiss,et,ou,petit,grand,egal,diff,peteg,grdeg,etx,oux,rshift,lshift,tercond,terelse;
714  char t;
715  TString slash("/"), escapedSlash("\\/");
716  Int_t inter2 = 0;
717  SetNumber(0);
718  Int_t actionCode,actionParam;
719  Int_t err_hint = 0;
720 
721  // Verify correct matching of parenthesis and remove unnecessary parenthesis.
722  lchain = chaine.Length();
723  //if (chaine(lchain-2,2) == "^2") chaine = "sq(" + chaine(0,lchain-2) + ")";
724  parenthese = kTRUE;
725  lchain = chaine.Length();
726  while (parenthese && lchain>0 && err==0){
727  compt = 0;
728  compt2 = 0;
729  inString = false;
730  lchain = chaine.Length();
731  if (lchain==0) err=4;
732  else {
733  for (i=1; i<=lchain; ++i) {
734  if (chaine(i-1,1) == "\"") inString = !inString;
735  if (!inString) {
736  if (chaine(i-1,1) == "[") compt2++;
737  if (chaine(i-1,1) == "]") compt2--;
738  if (chaine(i-1,1) == "(") compt++;
739  if (chaine(i-1,1) == ")") compt--;
740  }
741  if (compt < 0) err = 40; // more open parentheses than close parentheses
742  if (compt2< 0) err = 42; // more ] than [
743  if (compt==0 && (i!=lchain || lchain==1)) parenthese = kFALSE;
744  // if (lchain<3 && chaine(0,1)!="(" && chaine(lchain-1,1)!=")") parenthese = kFALSE;
745  }
746  if (compt > 0) err = 41; // more ( than )
747  if (compt2> 0) err = 43; // more [ than ]
748  if (parenthese) chaine = chaine(1,lchain-2);
749  }
750  } // while parantheses
751 
752  if (lchain==0) err=4; // empty string
753  modulo=plus=moins=multi=divi=puiss=et=ou=petit=grand=egal=diff=peteg=grdeg=etx=oux=rshift=lshift=tercond=terelse=0;
754 
755  // Look for simple operators
756 
757  if (err==0) {
758  compt = compt2 = compt3 = compt4 = 0;puiss10=0;puiss10bis = 0;
759  inString = false;
760  j = lchain;
761  Bool_t isdecimal = 1; // indicates whether the left part is decimal.
762 
763  for (i=1;i<=lchain; i++) {
764 
765  puiss10=puiss10bis=0;
766  if (i>2) {
767  t = chaine[i-3];
768  isdecimal = isdecimal && (strchr("0123456789.",t)!=0);
769  if (isdecimal) {
770  if ( chaine[i-2] == 'e' || chaine[i-2] == 'E' ) puiss10 = 1;
771  } else if ( strchr("+-/[]()&|><=!*/%^\\",t) ) {
772  isdecimal = 1; // reset after delimiter
773  }
774  }
775  if (j>2) {
776  if (chaine[j-2] == 'e' || chaine[j-2] == 'E') {
777  Bool_t isrightdecimal = 1;
778 
779  for(k=j-3; k>=0 && isrightdecimal; --k) {
780  t = chaine[k];
781  isrightdecimal = isrightdecimal && (strchr("0123456789.",t)!=0);
782  if (!isrightdecimal) {
783  if (strchr("+-/[]()&|><=!*/%^\\",t)!=0) {
784  puiss10bis = 1;
785  }
786  }
787  }
788  if (k<0 && isrightdecimal) puiss10bis = 1;
789  }
790  }
791  if (puiss10 && (i<=lchain)) {
792  t = chaine[i];
793  puiss10 = (strchr("0123456789.",t)!=0);
794  }
795  if (puiss10bis && (j<=lchain)) {
796  t = chaine[j];
797  puiss10bis = (strchr("0123456789.",t)!=0);
798  }
799 
800  if (chaine(i-1,1) == "\"") inString = !inString;
801  if (inString) continue;
802  if (chaine(i-1,1) == "[") compt2++;
803  if (chaine(i-1,1) == "]") compt2--;
804  if (chaine(i-1,1) == "(") compt++;
805  if (chaine(i-1,1) == ")") compt--;
806  if (chaine(j-1,1) == "[") compt3++;
807  if (chaine(j-1,1) == "]") compt3--;
808  if (chaine(j-1,1) == "(") compt4++;
809  if (chaine(j-1,1) == ")") compt4--;
810  if (chaine(i-1,2)=="&&" && !inString && compt==0 && compt2==0 && et==0) {et=i;puiss=0;}
811  if (chaine(i-1,2)=="||" && compt==0 && compt2==0 && ou==0) {puiss10=0; ou=i;}
812  if (chaine(i-1,1)=="&" && compt==0 && compt2==0 && etx==0) {etx=i;puiss=0;}
813  if (chaine(i-1,1)=="|" && compt==0 && compt2==0 && oux==0) {puiss10=0; oux=i;}
814  if (chaine(i-1,2)==">>" && compt==0 && compt2==0 && rshift==0) {puiss10=0; rshift=i;}
815  if (chaine(i-1,1)==">" && compt==0 && compt2==0 && rshift==0 && grand==0)
816  {puiss10=0; grand=i;}
817  if (chaine(i-1,2)=="<<" && compt==0 && compt2==0 && lshift==0) {puiss10=0; lshift=i;}
818  if (chaine(i-1,1)=="<" && compt==0 && compt2==0 && lshift==0 && petit==0)
819  {puiss10=0; petit=i;
820  // Check whether or not we have a template names! (actually this can
821  // only happen in TTreeFormula.
822  for(int ip = i,depth=0; ip < lchain; ++ip) {
823  char c = chaine(ip);
824  // The characteres allowed in the template parameter are alpha-numerical characters,
825  // underscores, comma, <, > and scope operator.
826  if (isalnum(c) || c=='_' || c==',') continue;
827  if (c==':' && chaine(ip+1)==':') { ++ip; continue; }
828  if (c=='<') { ++depth; continue; }
829  if (c=='>') {
830  if (depth) { --depth; continue; }
831  else {
832  // We reach the end of the template parameter.
833  petit = 0;
834  i = ip+1;
835  break;
836  }
837  }
838  // Character not authorized within a template parameter
839  break;
840  }
841  if (petit==0) {
842  // We found a template parameter and modified i
843  continue; // the for(int i ,...)
844  }
845  }
846  if ((chaine(i-1,2)=="<=" || chaine(i-1,2)=="=<") && compt==0 && compt2==0
847  && peteg==0) {peteg=i; puiss10=0; petit=0;}
848  if ((chaine(i-1,2)=="=>" || chaine(i-1,2)==">=") && compt==0 && compt2==0
849  && grdeg==0) {puiss10=0; grdeg=i; grand=0;}
850  if (chaine(i-1,2) == "==" && compt == 0 && compt2 == 0 && egal == 0) {puiss10=0; egal=i;}
851  if (chaine(i-1,2) == "!=" && compt == 0 && compt2 == 0 && diff == 0) {puiss10=0; diff=i;}
852  if (i>1 && chaine(i-1,1) == "+" && compt == 0 && compt2 == 0 && puiss10==0) plus=i;
853  if (chaine(j-1,1) == "-" && chaine(j-2,1) != "*" && chaine(j-2,1) != "/"
854  && chaine(j-2,1)!="^" && compt3==0 && compt4==0 && moins==0 && puiss10bis==0) moins=j;
855  if (chaine(i-1,1)=="%" && compt==0 && compt2==0 && modulo==0) {puiss10=0; modulo=i;}
856  if (chaine(i-1,1)=="*" && compt==0 && compt2==0 && multi==0) {puiss10=0; multi=i;}
857  if (chaine(j-1,1)=="/" && chaine(j-2,1)!="\\"
858  && compt4==0 && compt3==0 && divi==0)
859  {
860  puiss10=0; divi=j;
861  }
862  if (chaine(j-1)=='^' && compt4==0 && compt3==0 && puiss==0) {puiss10=0; puiss=j;}
863  if (chaine(i-1)=='?' && compt == 0 && compt2 == 0 && tercond == 0) {puiss10=0; tercond=i;}
864  if (chaine(i-1)==':' && tercond && compt == 0 && compt2 == 0 && terelse == 0) {
865  if (i>2 && chaine(i-2)!=':' && chaine(i)!=':') {
866  puiss10=0; terelse=i;
867  }
868  }
869 
870  j--;
871  }
872 
873  // If operator found, analyze left and right part of the statement
874 
875  actionParam = 0;
876  if (tercond && terelse) {
877  if (tercond == 1 || terelse == lchain || tercond == (terelse-1) ) {
878  err = 5;
879  chaine_error = "?:";
880  } else {
881  // Condition
882  ctemp = chaine(0,tercond-1);
883  Analyze(ctemp.Data(),err,offset); if (err) return;
884 
885  fExpr[fNoper] = "?: condition jump";
886  actionCode = kJumpIf;
887  actionParam = 0;
888  SetAction(fNoper,actionCode, actionParam);
889  Int_t optloc = fNoper++;
890 
891  // Expression executed if condition is true.
892  ctemp = chaine(tercond,terelse-tercond-1);
893  Analyze(ctemp.Data(),err,offset); if (err) return;
894  actionParam = fNoper; // We want to skip the next instruction ('else jump'), so we set the param to the current cursor and the next instruction will be skip by the ++i in the eval loop
895  SetAction(optloc, actionCode, actionParam);
896 
897  fExpr[fNoper] = "?: else jump";
898  actionCode = kJump;
899  actionParam = 0;
900  // Set jump target.
901  SetAction(fNoper,actionCode, actionParam);
902  optloc = fNoper++;
903 
904  // Expression executed if condition is false.
905  ctemp = chaine(terelse,lchain-terelse);
906  Analyze(ctemp.Data(),err,offset); if (err) return;
907  // Set jump target.
908  actionParam = fNoper - 1; // We need to not skip the next instruction, so we compensate for the ++i in the eval loop
909  SetAction(optloc, actionCode, actionParam);
910 
911  if (IsString(optloc-1) != IsString(fNoper-1)) {
912  err = 45;
913  chaine_error = "?:";
914  }
915  }
916  } else if (ou != 0) { //check for ||
917  if (ou==1 || ou==lchain-1) {
918  err=5;
919  chaine_error="||";
920  }
921  else {
922  ctemp = chaine(0,ou-1);
923  Analyze(ctemp.Data(),err,offset); if (err) return;
924 
925  fExpr[fNoper] = "|| checkpoint";
926  actionCode = kBoolOptimize;
927  actionParam = 2;
928  SetAction(fNoper,actionCode, actionParam);
929  Int_t optloc = fNoper++;
930 
931  ctemp = chaine(ou+1,lchain-ou-1);
932  Analyze(ctemp.Data(),err,offset); if (err) return;
933  fExpr[fNoper] = "||";
934  actionCode = kOr;
935  SetAction(fNoper,actionCode, 0);
936 
937  SetAction( optloc, GetAction(optloc), GetActionParam(optloc) + (fNoper-optloc) * 10);
938  fNoper++;
939  if (!CheckOperands(optloc-1,fNoper-1,err)) return;
940  }
941  } else if (et!=0) {
942  if (et==1 || et==lchain-1) {
943  err=5;
944  chaine_error="&&";
945  }
946  else {
947  ctemp = chaine(0,et-1);
948  Analyze(ctemp.Data(),err,offset); if (err) return;
949 
950  fExpr[fNoper] = "&& checkpoint";
951  actionCode = kBoolOptimize;
952  actionParam = 1;
953  SetAction(fNoper,actionCode,actionParam);
954 
955  Int_t optloc = fNoper++;
956 
957  ctemp = chaine(et+1,lchain-et-1);
958  Analyze(ctemp.Data(),err,offset); if (err) return;
959  fExpr[fNoper] = "&&";
960  actionCode = kAnd;
961  SetAction(fNoper,actionCode,0);
962 
963  SetAction(optloc, GetAction(optloc), GetActionParam(optloc) + (fNoper-optloc) * 10);
964  fNoper++;
965  if (!CheckOperands(optloc-1,fNoper-1,err)) return;
966  }
967  } else if (oux!=0) {
968  if (oux==1 || oux==lchain) {
969  err=5;
970  chaine_error="|";
971  }
972  else {
973  ctemp = chaine(0,oux-1);
974  Analyze(ctemp.Data(),err,offset); if (err) return;
975  UInt_t leftopr = fNoper-1;
976  ctemp = chaine(oux,lchain-oux);
977  Analyze(ctemp.Data(),err,offset); if (err) return;
978  fExpr[fNoper] = "|";
979  actionCode = kBitOr;
980  SetAction(fNoper,actionCode,actionParam);
981  fNoper++;
982  if (!CheckOperands(leftopr,fNoper-1,err)) return;
983  }
984  } else if (etx!=0) {
985  if (etx==1 || etx==lchain) {
986  err=5;
987  chaine_error="&";
988  }
989  else {
990  ctemp = chaine(0,etx-1);
991  Analyze(ctemp.Data(),err,offset); if (err) return;
992  UInt_t leftopr = fNoper-1;
993  ctemp = chaine(etx,lchain-etx);
994  Analyze(ctemp.Data(),err,offset); if (err) return;
995  fExpr[fNoper] = "&";
996  actionCode = kBitAnd;
997  SetAction(fNoper,actionCode,actionParam);
998  fNoper++;
999  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1000  }
1001  } else if (petit != 0) {
1002  if (petit==1 || petit==lchain) {
1003  err=5;
1004  chaine_error="<";
1005  }
1006  else {
1007  ctemp = chaine(0,petit-1);
1008  Analyze(ctemp.Data(),err,offset); if (err) return;
1009  UInt_t leftopr = fNoper-1;
1010  ctemp = chaine(petit,lchain-petit);
1011  Analyze(ctemp.Data(),err,offset); if (err) return;
1012  fExpr[fNoper] = "<";
1013  actionCode = kLess;
1014  SetAction(fNoper,actionCode,actionParam);
1015  fNoper++;
1016  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1017  }
1018  } else if (grand != 0) {
1019  if (grand==1 || grand==lchain) {
1020  err=5;
1021  chaine_error=">";
1022  }
1023  else {
1024  ctemp = chaine(0,grand-1);
1025  Analyze(ctemp.Data(),err,offset); if (err) return;
1026  UInt_t leftopr = fNoper-1;
1027  ctemp = chaine(grand,lchain-grand);
1028  Analyze(ctemp.Data(),err,offset); if (err) return;
1029  fExpr[fNoper] = ">";
1030  actionCode = kGreater;
1031  SetAction(fNoper,actionCode,actionParam);
1032  fNoper++;
1033  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1034  }
1035  } else if (peteg != 0) {
1036  if (peteg==1 || peteg==lchain-1) {
1037  err=5;
1038  chaine_error="<=";
1039  }
1040  else {
1041  ctemp = chaine(0,peteg-1);
1042  Analyze(ctemp.Data(),err,offset); if (err) return;
1043  ctemp = chaine(peteg+1,lchain-peteg-1);
1044  UInt_t leftopr = fNoper-1;
1045  Analyze(ctemp.Data(),err,offset); if (err) return;
1046  fExpr[fNoper] = "<=";
1047  actionCode = kLessThan;
1048  SetAction(fNoper,actionCode,actionParam);
1049  fNoper++;
1050  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1051  }
1052  } else if (grdeg != 0) {
1053  if (grdeg==1 || grdeg==lchain-1) {
1054  err=5;
1055  chaine_error="=>";
1056  }
1057  else {
1058  ctemp = chaine(0,grdeg-1);
1059  Analyze(ctemp.Data(),err,offset); if (err) return;
1060  UInt_t leftopr = fNoper-1;
1061  ctemp = chaine(grdeg+1,lchain-grdeg-1);
1062  Analyze(ctemp.Data(),err,offset); if (err) return;
1063  fExpr[fNoper] = ">=";
1064  actionCode = kGreaterThan;
1065  SetAction(fNoper,actionCode,actionParam);
1066  fNoper++;
1067  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1068  }
1069  } else if (egal != 0) {
1070  if (egal==1 || egal==lchain-1) {
1071  err=5;
1072  chaine_error="==";
1073  }
1074  else {
1075  ctemp = chaine(0,egal-1);
1076  Analyze(ctemp.Data(),err,offset); if (err) return;
1077  Int_t optloc = fNoper-1;
1078 
1079  ctemp = chaine(egal+1,lchain-egal-1);
1080  Analyze(ctemp.Data(),err,offset); if (err) return;
1081  fExpr[fNoper] = "==";
1082  actionCode = kEqual;
1083 
1084  Bool_t isstring = IsString(fNoper-1);
1085  if (IsString(optloc) != isstring) {
1086  err = 45;
1087  chaine_error = "==";
1088  } else if (isstring) {
1089  actionCode = kStringEqual;
1090  }
1091  SetAction(fNoper,actionCode,actionParam);
1092  fNoper++;
1093  }
1094  } else if (diff != 0) {
1095  if (diff==1 || diff==lchain-1) {
1096  err=5;
1097  chaine_error = "!=";
1098  }
1099  else {
1100  ctemp = chaine(0,diff-1);
1101  Analyze(ctemp.Data(),err,offset); if (err) return;
1102  Int_t optloc = fNoper-1;
1103 
1104  ctemp = chaine(diff+1,lchain-diff-1);
1105  Analyze(ctemp.Data(),err,offset); if (err) return;
1106  fExpr[fNoper] = "!=";
1107  actionCode = kNotEqual;
1108 
1109  Bool_t isstring = IsString(fNoper-1);
1110  if (IsString(optloc) != isstring) {
1111  err = 45;
1112  chaine_error = "!=";
1113  } else if (isstring) {
1114  actionCode = kStringNotEqual;
1115  }
1116  SetAction(fNoper,actionCode,actionParam);
1117  fNoper++;
1118  }
1119  } else if (plus != 0) {
1120  if (plus==lchain) {
1121  err=5;
1122  chaine_error = "+";
1123  }
1124  else {
1125  ctemp = chaine(0,plus-1);
1126  Analyze(ctemp.Data(),err,offset); if (err) return;
1127  UInt_t leftopr = fNoper-1;
1128  ctemp = chaine(plus,lchain-plus);
1129  Analyze(ctemp.Data(),err,offset); if (err) return;
1130  fExpr[fNoper] = "+";
1131  actionCode = kAdd;
1132  SetAction(fNoper,actionCode,actionParam);
1133  fNoper++;
1134  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1135  }
1136  } else {
1137  if (moins != 0) {
1138  if (moins == 1) {
1139  ctemp = chaine(moins,lchain-moins);
1140  Analyze(ctemp.Data(),err,offset); if (err) return;
1141  fExpr[fNoper] = "-";
1142  actionCode = kSignInv;
1143  SetAction(fNoper,actionCode,actionParam);
1144  ++fNoper;
1145  if (!CheckOperands(fNoper-1,err)) return;
1146  } else {
1147  if (moins == lchain) {
1148  err=5;
1149  chaine_error = "-";
1150  } else {
1151  ctemp = chaine(0,moins-1);
1152  Analyze(ctemp.Data(),err,offset); if (err) return;
1153  UInt_t leftopr = fNoper-1;
1154  ctemp = chaine(moins,lchain-moins);
1155  Analyze(ctemp.Data(),err,offset); if (err) return;
1156  fExpr[fNoper] = "-";
1157  actionCode = kSubstract;
1158  SetAction(fNoper,actionCode,actionParam);
1159  fNoper++;
1160  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1161  }
1162  }
1163  } else if (modulo != 0) {
1164  if (modulo == 1 || modulo == lchain) {
1165  err=5;
1166  chaine_error="%";
1167  } else {
1168  ctemp = chaine(0,modulo-1);
1169  Analyze(ctemp.Data(),err,offset); if (err) return;
1170  UInt_t leftopr = fNoper-1;
1171  ctemp = chaine(modulo,lchain-modulo);
1172  Analyze(ctemp.Data(),err,offset); if (err) return;
1173  fExpr[fNoper] = "%";
1174  actionCode = kModulo;
1175  SetAction(fNoper,actionCode,actionParam);
1176  fNoper++;
1177  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1178  }
1179  } else if (rshift != 0) {
1180  if (rshift == 1 || rshift == lchain) {
1181  err=5;
1182  chaine_error=">>";
1183  } else {
1184  ctemp = chaine(0,rshift-1);
1185  Analyze(ctemp.Data(),err,offset); if (err) return;
1186  UInt_t leftopr = fNoper-1;
1187  ctemp = chaine(rshift+1,lchain-rshift-1);
1188  Analyze(ctemp.Data(),err,offset); if (err) return;
1189  fExpr[fNoper] = ">>";
1190  actionCode = kRightShift;
1191  SetAction(fNoper,actionCode,actionParam);
1192  fNoper++;
1193  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1194  }
1195  } else if (lshift != 0) {
1196  if (lshift == 1 || lshift == lchain) {
1197  err=5;
1198  chaine_error=">>";
1199  } else {
1200  ctemp = chaine(0,lshift-1);
1201  Analyze(ctemp.Data(),err,offset); if (err) return;
1202  UInt_t leftopr = fNoper-1;
1203  ctemp = chaine(lshift+1,lchain-lshift-1);
1204  Analyze(ctemp.Data(),err,offset); if (err) return;
1205  fExpr[fNoper] = ">>";
1206  actionCode = kLeftShift;
1207  SetAction(fNoper,actionCode,actionParam);
1208  fNoper++;
1209  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1210  }
1211  } else {
1212  if (multi != 0) {
1213  if (multi == 1 || multi == lchain) {
1214  err=5;
1215  chaine_error="*";
1216  }
1217  else {
1218  ctemp = chaine(0,multi-1);
1219  Analyze(ctemp.Data(),err,offset); if (err) return;
1220  UInt_t leftopr = fNoper-1;
1221  ctemp = chaine(multi,lchain-multi);
1222  Analyze(ctemp.Data(),err,offset); if (err) return;
1223  fExpr[fNoper] = "*";
1224  actionCode = kMultiply;
1225  SetAction(fNoper,actionCode,actionParam);
1226  fNoper++;
1227  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1228  }
1229  } else {
1230  if (divi != 0) {
1231  if (divi == 1 || divi == lchain) {
1232  err=5;
1233  chaine_error = "/";
1234  }
1235  else {
1236  ctemp = chaine(0,divi-1);
1237  Analyze(ctemp.Data(),err,offset); if (err) return;
1238  UInt_t leftopr = fNoper-1;
1239  ctemp = chaine(divi,lchain-divi);
1240  Analyze(ctemp.Data(),err,offset); if (err) return;
1241  fExpr[fNoper] = "/";
1242  actionCode = kDivide;
1243  SetAction(fNoper,actionCode,actionParam);
1244  fNoper++;
1245  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1246  }
1247  } else {
1248  if (puiss != 0) {
1249  if (puiss == 1 || puiss == lchain) {
1250  err = 5;
1251  chaine_error = "**";
1252  }
1253  else {
1254  if (chaine(lchain-2,2) == "^2") {
1255  ctemp = "sq(" + chaine(0,lchain-2) + ")";
1256  Analyze(ctemp.Data(),err,offset); if (err) return;
1257  } else {
1258  ctemp = chaine(0,puiss-1);
1259  Analyze(ctemp.Data(),err,offset); if (err) return;
1260  UInt_t leftopr = fNoper-1;
1261  ctemp = chaine(puiss,lchain-puiss);
1262  Analyze(ctemp.Data(),err,offset); if (err) return;
1263  fExpr[fNoper] = "^";
1264  actionCode = kpow;
1265  SetAction(fNoper,actionCode,actionParam);
1266  fNoper++;
1267  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1268  }
1269  }
1270  } else {
1271 
1272  find=0;
1273 
1274  // Check for a numerical expression
1275  {
1276  Bool_t hasDot = kFALSE;
1277  Bool_t isHexa = kFALSE;
1278  Bool_t hasExpo= kFALSE;
1279  if ((chaine(0,2)=="0x")||(chaine(0,2)=="0X")) isHexa=kTRUE;
1280  for (j=0; j<chaine.Length() && err==0; j++) {
1281  t=chaine[j];
1282  if (!isHexa) {
1283  if (j>0 && (chaine(j,1)=="e" || chaine(j,2)=="e+" || chaine(j,2)=="e-" || chaine(j,1)=="E" || chaine(j,2)=="E+" || chaine(j,2)=="E-")) {
1284  if (hasExpo) {
1285  err=26;
1286  chaine_error=chaine;
1287  }
1288  hasExpo = kTRUE;
1289  // The previous implementation allowed a '.' in the exponent.
1290  // That information was ignored (by sscanf), we now make it an error
1291  // hasDot = kFALSE;
1292  hasDot = kTRUE; // forbid any additional '.'
1293  if (chaine(j,2)=="e+" || chaine(j,2)=="e-" || chaine(j,2)=="E+" || chaine(j,2)=="E-") j++;
1294  }
1295  else {
1296  if (chaine(j,1) == "." && !hasDot) hasDot = kTRUE; // accept only one '.' in the number
1297  else {
1298  // The previous implementation was allowing ANYTHING after the '.' and thus
1299  // made legal code like '2.3 and fpx' and was just silently ignoring the
1300  // 'and fpx'.
1301  if (!strchr("0123456789",t) && (chaine(j,1)!="+" || j!=0)) {
1302  err = 30;
1303  chaine_error=chaine;
1304  }
1305  }
1306  }
1307  }
1308  else {
1309  if (!strchr("0123456789abcdefABCDEF",t) && (j>1)) {
1310  err = 30;
1311  chaine_error=chaine;
1312  }
1313  }
1314  }
1315  if (fNconst >= gMAXCONST) err = 27;
1316  if (!err) {
1317  if (!isHexa) {if (sscanf((const char*)chaine,"%lg",&vafConst) > 0) err = 0; else err =1;}
1318  else {if (sscanf((const char*)chaine,"%lx",&vafConst2) > 0) err = 0; else err=1;
1319  vafConst = (Double_t) vafConst2;}
1320  fExpr[fNoper] = chaine;
1321  k = -1;
1322  for (j=0;j<fNconst;j++) {
1323  if (vafConst == fConst[j] ) k= j;
1324  }
1325  if ( k < 0) { k = fNconst; fNconst++; fConst[k] = vafConst; }
1326  actionCode = kConstant;
1327  actionParam = k;
1328  SetAction(fNoper,actionCode,actionParam);
1329  fNoper++;
1330  }
1331  if (err==30) err=0;
1332  else find = kTRUE;
1333  }
1334 
1335  // Look for an already defined expression
1336 
1337  if (find==0) {
1338  {
1340  oldformula = (const TFormula*)gROOT->GetListOfFunctions()->FindObject((const char*)chaine);
1341  }
1342  if (oldformula && strcmp(schain,oldformula->GetTitle())) {
1343  Int_t nprior = fNpar;
1344  Analyze(oldformula->GetExpFormula(),err,fNpar);
1345  // if the oldformula was using a normalized function (gausn or landaun) set also in this one
1346  if (oldformula->IsNormalized()) SetBit(kNormalized);
1347  if (err) return; // changes fNpar
1348  fNpar = nprior;
1349  find=1;
1350  if (!err) {
1351  Int_t npold = oldformula->GetNpar();
1352  fNpar += npold;
1353  for (Int_t ipar=0;ipar<npold;ipar++) {
1354  fParams[ipar+fNpar-npold] = oldformula->GetParameter(ipar);
1355  }
1356  }
1357  }
1358  }
1359  if (find == 0) {
1360 
1361  // Check if chaine is a defined variable.
1362  // Note that DefinedVariable can be overloaded
1363 
1364  ctemp = chaine;
1365  ctemp.ReplaceAll(escapedSlash, slash);
1366  Int_t action;
1367  k = DefinedVariable(ctemp,action);
1368  if (k==-3) {
1369  // Error message already issued
1370  err = 1;
1371  } if (k==-2) {
1372  err = 31;
1373  chaine_error = ctemp;
1374  } else if ( k >= 0 ) {
1375  fExpr[fNoper] = ctemp;
1376  actionCode = action;
1377  actionParam = k;
1378  SetAction(fNoper,actionCode,actionParam);
1379  if (action==kDefinedString) fNstring++;
1380  else if (k <kMAXFOUND && !fAlreadyFound.TestBitNumber(k)) {
1381  fAlreadyFound.SetBitNumber(k);
1382  fNval++;
1383  }
1384  fNoper++;
1385  } else if (chaine(0,1) == "!") {
1386  ctemp = chaine(1,lchain-1);
1387  Analyze(ctemp.Data(),err,offset); if (err) return;
1388  fExpr[fNoper] = "!";
1389  actionCode = kNot;
1390  SetAction(fNoper,actionCode,actionParam);
1391  fNoper++;
1392  if (!CheckOperands(fNoper-1,err)) return;
1393  } else if (chaine(0,1)=="\"" && chaine(chaine.Length()-1,1)=="\"") {
1394  // It is a string !!!
1395  fExpr[fNoper] = chaine(1,chaine.Length()-2);
1396  actionCode = kStringConst;
1397  SetAction(fNoper,actionCode,actionParam);
1398  fNoper++;
1399  } else if (chaine(0,4) == "cos(") {
1400  ctemp = chaine(3,lchain-3);
1401  Analyze(ctemp.Data(),err,offset); if (err) return;
1402  fExpr[fNoper] = "cos";
1403  actionCode = kcos;
1404  SetAction(fNoper,actionCode,actionParam);
1405  fNoper++;
1406  if (!CheckOperands(fNoper-1,err)) return;
1407  } else if (chaine(0,4) == "sin(") {
1408  ctemp = chaine(3,lchain-3);
1409  Analyze(ctemp.Data(),err,offset); if (err) return;
1410  fExpr[fNoper] = "sin";
1411  actionCode = ksin;
1412  SetAction(fNoper,actionCode,actionParam);
1413  fNoper++;
1414  if (!CheckOperands(fNoper-1,err)) return;
1415  } else if (chaine(0,4) == "tan(") {
1416  ctemp = chaine(3,lchain-3);
1417  Analyze(ctemp.Data(),err,offset); if (err) return;
1418  fExpr[fNoper] = "tan";
1419  actionCode = ktan;
1420  SetAction(fNoper,actionCode,actionParam);
1421  fNoper++;
1422  if (!CheckOperands(fNoper-1,err)) return;
1423  } else if (chaine(0,5) == "acos(") {
1424  ctemp = chaine(4,lchain-4);
1425  Analyze(ctemp.Data(),err,offset); if (err) return;
1426  fExpr[fNoper] = "acos";
1427  actionCode = kacos;
1428  SetAction(fNoper,actionCode,actionParam);
1429  fNoper++;
1430  if (!CheckOperands(fNoper-1,err)) return;
1431  } else if (chaine(0,5) == "asin(") {
1432  ctemp = chaine(4,lchain-4);
1433  Analyze(ctemp.Data(),err,offset); if (err) return;
1434  fExpr[fNoper] = "asin";
1435  actionCode = kasin;
1436  SetAction(fNoper,actionCode,actionParam);
1437  fNoper++;
1438  if (!CheckOperands(fNoper-1,err)) return;
1439  } else if (chaine(0,5) == "atan(") {
1440  ctemp = chaine(4,lchain-4);
1441  Analyze(ctemp.Data(),err,offset); if (err) return;
1442  fExpr[fNoper] = "atan";
1443  actionCode = katan;
1444  SetAction(fNoper,actionCode,actionParam);
1445  fNoper++;
1446  if (!CheckOperands(fNoper-1,err)) return;
1447  } else if (chaine(0,5) == "cosh(") {
1448  ctemp = chaine(4,lchain-4);
1449  Analyze(ctemp.Data(),err,offset); if (err) return;
1450  fExpr[fNoper] = "cosh";
1451  actionCode = kcosh;
1452  SetAction(fNoper,actionCode,actionParam);
1453  fNoper++;
1454  if (!CheckOperands(fNoper-1,err)) return;
1455  } else if (chaine(0,5) == "sinh(") {
1456  ctemp = chaine(4,lchain-4);
1457  Analyze(ctemp.Data(),err,offset); if (err) return;
1458  fExpr[fNoper] = "sinh";
1459  actionCode = ksinh;
1460  SetAction(fNoper,actionCode,actionParam);
1461  fNoper++;;
1462  if (!CheckOperands(fNoper-1,err)) return;
1463  } else if (chaine(0,5) == "tanh(") {
1464  ctemp = chaine(4,lchain-4);
1465  Analyze(ctemp.Data(),err,offset); if (err) return;
1466  fExpr[fNoper] = "tanh";
1467  actionCode = ktanh;
1468  SetAction(fNoper,actionCode,actionParam);
1469  fNoper++;;
1470  if (!CheckOperands(fNoper-1,err)) return;
1471  } else if (chaine(0,6) == "acosh(") {
1472  ctemp = chaine(5,lchain-5);
1473  Analyze(ctemp.Data(),err,offset); if (err) return;
1474  fExpr[fNoper] = "acosh";
1475  actionCode = kacosh;
1476  SetAction(fNoper,actionCode,actionParam);
1477  fNoper++;;
1478  if (!CheckOperands(fNoper-1,err)) return;
1479  } else if (chaine(0,6) == "asinh(") {
1480  ctemp = chaine(5,lchain-5);
1481  Analyze(ctemp.Data(),err,offset); if (err) return;
1482  fExpr[fNoper] = "asinh";
1483  actionCode = kasinh;
1484  SetAction(fNoper,actionCode,actionParam);
1485  fNoper++;;
1486  if (!CheckOperands(fNoper-1,err)) return;
1487  } else if (chaine(0,6) == "atanh(") {
1488  ctemp = chaine(5,lchain-5);
1489  Analyze(ctemp.Data(),err,offset); if (err) return;
1490  fExpr[fNoper] = "atanh";
1491  actionCode = katanh;
1492  SetAction(fNoper,actionCode,actionParam);
1493  fNoper++;;
1494  if (!CheckOperands(fNoper-1,err)) return;
1495  } else if (chaine(0,3) == "sq(") {
1496  ctemp = chaine(2,lchain-2);
1497  Analyze(ctemp.Data(),err,offset); if (err) return;
1498  fExpr[fNoper] = "sq";
1499  actionCode = ksq;
1500  SetAction(fNoper,actionCode,actionParam);
1501  fNoper++;;
1502  if (!CheckOperands(fNoper-1,err)) return;
1503  } else if (chaine(0,4) == "log(") {
1504  ctemp = chaine(3,lchain-3);
1505  Analyze(ctemp.Data(),err,offset); if (err) return;
1506  fExpr[fNoper] = "log";
1507  actionCode = klog;
1508  SetAction(fNoper,actionCode,actionParam);
1509  fNoper++;;
1510  if (!CheckOperands(fNoper-1,err)) return;
1511  } else if (chaine(0,6) == "log10(") {
1512  ctemp = chaine(5,lchain-5);
1513  Analyze(ctemp.Data(),err,offset); if (err) return;
1514  fExpr[fNoper] = "log10";
1515  actionCode = klog10;
1516  SetAction(fNoper,actionCode,actionParam);
1517  fNoper++;;
1518  if (!CheckOperands(fNoper-1,err)) return;
1519  } else if (chaine(0,4) == "exp(") {
1520  ctemp = chaine(3,lchain-3);
1521  Analyze(ctemp.Data(),err,offset); if (err) return;
1522  fExpr[fNoper] = "exp";
1523  actionCode = kexp;
1524  SetAction(fNoper,actionCode,actionParam);
1525  fNoper++;;
1526  if (!CheckOperands(fNoper-1,err)) return;
1527  } else if (chaine(0,4) == "abs(") {
1528  ctemp = chaine(3,lchain-3);
1529  Analyze(ctemp.Data(),err,offset); if (err) return;
1530  fExpr[fNoper] = "abs";
1531  actionCode = kabs;
1532  SetAction(fNoper,actionCode,actionParam);
1533  fNoper++;;
1534  if (!CheckOperands(fNoper-1,err)) return;
1535  } else if (chaine(0,5) == "sign(") {
1536  ctemp = chaine(4,lchain-4);
1537  Analyze(ctemp.Data(),err,offset); if (err) return;
1538  fExpr[fNoper] = "sign";
1539  actionCode = ksign;
1540  SetAction(fNoper,actionCode,actionParam);
1541  fNoper++;;
1542  if (!CheckOperands(fNoper-1,err)) return;
1543  } else if (chaine(0,4) == "int(") {
1544  ctemp = chaine(3,lchain-3);
1545  Analyze(ctemp.Data(),err,offset); if (err) return;
1546  fExpr[fNoper] = "int";
1547  actionCode = kint;
1548  SetAction(fNoper,actionCode,actionParam);
1549  fNoper++;;
1550  if (!CheckOperands(fNoper-1,err)) return;
1551  } else if (chaine == "rndm" || chaine(0,5) == "rndm(") {
1552  fExpr[fNoper] = "rndm";
1553  actionCode = krndm;
1554  SetAction(fNoper,actionCode,actionParam);
1555  fNoper++;;
1556  } else if (chaine(0,5) == "sqrt(") {
1557  ctemp = chaine(4,lchain-4);
1558  Analyze(ctemp.Data(),err,offset); if (err) return;
1559  fExpr[fNoper] = "sqrt";
1560  actionCode = ksqrt;
1561  SetAction(fNoper,actionCode,actionParam);
1562  fNoper++;;
1563  if (!CheckOperands(fNoper-1,err)) return;
1564 
1565  // Look for an exponential
1566 
1567  } else if ( chaine == "expo" || chaine(0,5)=="expo("
1568  || (lchain==5 && chaine(1,4)=="expo")
1569  || (lchain==6 && chaine(2,4)=="expo")
1570  || chaine(1,5)=="expo(" || chaine(2,5)=="expo(" ) {
1571  chaine1ST=chaine;
1572  if (chaine(1,4) == "expo") {
1573  ctemp=chaine(0,1);
1574  if (ctemp=="x") {
1575  inter2=0;
1576  if (fNdim < 1) fNdim = 1; }
1577  else if (ctemp=="y") {
1578  inter2=1;
1579  if (fNdim < 2) fNdim = 2; }
1580  else if (ctemp=="z") {
1581  inter2=2;
1582  if (fNdim < 3) fNdim = 3; }
1583  else if (ctemp=="t") {
1584  inter2=3;
1585  if (fNdim < 4) fNdim = 4; }
1586  else {
1587  err=26; // unknown name;
1588  chaine_error=chaine1ST;
1589  }
1590  chaine=chaine(1,lchain-1);
1591  lchain=chaine.Length();
1592  } else inter2=0;
1593  if (chaine(2,4) == "expo") {
1594  if (chaine(0,2) != "xy") {
1595  err=26; // unknown name
1596  chaine_error=chaine1ST;
1597  }
1598  else {
1599  inter2=5;
1600  if (fNdim < 2) fNdim = 2;
1601  chaine=chaine(2,lchain-2);
1602  lchain=chaine.Length();
1603  }
1604  }
1605  if (lchain == 4) {
1606  if (fNpar>=gMAXPAR) err=7; // too many parameters
1607  if (!err) {
1608  fExpr[fNoper] = chaine1ST;
1609  actionCode = kexpo + inter2;
1610  actionParam = offset;
1611  SetAction(fNoper,actionCode,actionParam);
1612  if (inter2 == 5+offset && fNpar < 3+offset) fNpar = 3+offset;
1613  if (fNpar < 2+offset) fNpar = 2+offset;
1614  if (fNpar>=gMAXPAR) err=7; // too many parameters
1615  if (!err) {
1616  fNoper++;
1617  if (fNdim < 1) fNdim = 1;
1618  if (fNpar == 2) SetNumber(200);
1619  }
1620  }
1621  } else if (chaine(4,1) == "(") {
1622  ctemp = chaine(5,lchain-6);
1623  fExpr[fNoper] = chaine1ST;
1624  for (j=0; j<ctemp.Length(); j++) {
1625  t=ctemp[j];
1626  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1627  err=20;
1628  chaine_error=chaine1ST;
1629  }
1630  }
1631  if (err==0) {
1632  sscanf(ctemp.Data(),"%d",&inter);
1633  if (inter>=0) {
1634  inter += offset;
1635  actionCode = kexpo + inter2;
1636  actionParam = inter;
1637  SetAction(fNoper,actionCode,actionParam);
1638  if (inter2 == 5) inter++;
1639  if (inter+2>fNpar) fNpar = inter+2;
1640  if (fNpar>=gMAXPAR) err=7; // too many parameters
1641  if (!err) fNoper++;
1642  if (fNpar == 2) SetNumber(200);
1643  } else err=20;
1644  } else err = 20; // non integer value for parameter number
1645  } else {
1646  err=26; // unknown name
1647  chaine_error=chaine;
1648  }
1649 
1650  // Look for gaus, xgaus,ygaus,xygaus
1651 
1652  } else if (chaine=="gaus"
1653  || (lchain==5 && chaine(1,4)=="gaus")
1654  || (lchain==6 && chaine(2,4)=="gaus")
1655  || chaine(0,5)=="gaus(" || chaine(1,5)=="gaus(" || chaine(2,5)=="gaus(") {
1656  chaine1ST=chaine;
1657  if (chaine(1,4) == "gaus") {
1658  ctemp=chaine(0,1);
1659  if (ctemp=="x") {
1660  inter2=0;
1661  if (fNdim < 1) fNdim = 1; }
1662  else if (ctemp=="y") {
1663  inter2=1;
1664  if (fNdim < 2) fNdim = 2; }
1665  else if (ctemp=="z") {
1666  inter2=2;
1667  if (fNdim < 3) fNdim = 3; }
1668  else if (ctemp=="t") {
1669  inter2=3;
1670  if (fNdim < 4) fNdim = 4; }
1671  else {
1672  err=26; // unknown name
1673  chaine_error=chaine1ST;
1674  }
1675  chaine=chaine(1,lchain-1);
1676  lchain=chaine.Length();
1677  } else inter2=0;
1678  if (chaine(2,4) == "gaus") {
1679  if (chaine(0,2) != "xy") {
1680  err=26; // unknown name
1681  chaine_error=chaine1ST;
1682  }
1683  else {
1684  inter2=5;
1685  if (fNdim < 2) fNdim = 2;
1686  chaine=chaine(2,lchain-2);
1687  lchain=chaine.Length();
1688  SetNumber(110); // xygaus
1689  }
1690  }
1691  if (lchain == 4 && err==0) {
1692  if (fNpar>=gMAXPAR) err=7; // too many parameters
1693  if (!err) {
1694  fExpr[fNoper] = chaine1ST;
1695  actionCode = kgaus + inter2;
1696  actionParam = offset;
1697  SetAction(fNoper,actionCode,actionParam);
1698  if (inter2 == 5+offset && fNpar < 5+offset) fNpar = 5+offset;
1699  if (3+offset>fNpar) fNpar = 3+offset;
1700  if (fNpar>=gMAXPAR) err=7; // too many parameters
1701  if (!err) {
1702  fNoper++;
1703  if (fNdim < 1) fNdim = 1;
1704  if (fNpar == 3) SetNumber(100);
1705  }
1706  }
1707  } else if (chaine(4,1) == "(" && err==0) {
1708  ctemp = chaine(5,lchain-6);
1709  fExpr[fNoper] = chaine1ST;
1710  for (j=0; j<ctemp.Length(); j++) {
1711  t=ctemp[j];
1712  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1713  err=20;
1714  chaine_error=chaine1ST;
1715  }
1716  }
1717  if (err==0) {
1718  sscanf(ctemp.Data(),"%d",&inter);
1719  if (inter >= 0) {
1720  inter += offset;
1721  actionCode = kgaus + inter2;
1722  actionParam = inter;
1723  SetAction(fNoper,actionCode,actionParam);
1724  if (inter2 == 5) inter += 2;
1725  if (inter+3>fNpar) fNpar = inter+3;
1726  if (fNpar>=gMAXPAR) err=7; // too many parameters
1727  if (!err) fNoper++;
1728  if(fNpar == 3) SetNumber(100);
1729  } else err = 20; // non integer value for parameter number
1730  }
1731  } else if (err==0) {
1732  err=26; // unknown name
1733  chaine_error=chaine1ST;
1734  }
1735 
1736  // Look for landau, xlandau,ylandau,xylandau
1737 
1738  } else if (chaine=="landau" || (lchain==7 && chaine(1,6)=="landau")
1739  || (lchain==8 && chaine(2,6)=="landau")
1740  || chaine(0,7)=="landau(" || chaine(1,7)=="landau(" || chaine(2,7)=="landau(") {
1741  chaine1ST=chaine;
1742  if (chaine(1,6) == "landau") {
1743  ctemp=chaine(0,1);
1744  if (ctemp=="x") {
1745  inter2=0;
1746  if (fNdim < 1) fNdim = 1; }
1747  else if (ctemp=="y") {
1748  inter2=1;
1749  if (fNdim < 2) fNdim = 2; }
1750  else if (ctemp=="z") {
1751  inter2=2;
1752  if (fNdim < 3) fNdim = 3; }
1753  else if (ctemp=="t") {
1754  inter2=3;
1755  if (fNdim < 4) fNdim = 4; }
1756  else {
1757  err=26; // unknown name
1758  chaine_error=chaine1ST;
1759  }
1760  chaine=chaine(1,lchain-1);
1761  lchain=chaine.Length();
1762  } else inter2=0;
1763  if (chaine(2,6) == "landau") {
1764  if (chaine(0,2) != "xy") {
1765  err=26; // unknown name
1766  chaine_error=chaine1ST;
1767  }
1768  else {
1769  inter2=5;
1770  if (fNdim < 2) fNdim = 2;
1771  chaine=chaine(2,lchain-2);
1772  lchain=chaine.Length();
1773  SetNumber(410);
1774  }
1775  }
1776  if (lchain == 6 && err==0) {
1777  if (fNpar>=gMAXPAR) err=7; // too many parameters
1778  if (!err) {
1779  fExpr[fNoper] = chaine1ST;
1780  actionCode = klandau + inter2;
1781  actionParam = offset;
1782  SetAction(fNoper,actionCode,actionParam);
1783  if (inter2 == 5+offset && fNpar < 5+offset) fNpar = 5+offset;
1784  if (3+offset>fNpar) fNpar = 3+offset;
1785  if (fNpar>=gMAXPAR) err=7; // too many parameters
1786  if (!err) {
1787  fNoper++;
1788  if (fNdim < 1) fNdim = 1;
1789  if (fNpar == 3) SetNumber(400);
1790  }
1791  }
1792  } else if (chaine(6,1) == "(" && err==0) {
1793  ctemp = chaine(7,lchain-8);
1794  fExpr[fNoper] = chaine1ST;
1795  for (j=0; j<ctemp.Length(); j++) {
1796  t=ctemp[j];
1797  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1798  err=20;
1799  chaine_error=chaine1ST;
1800  }
1801  }
1802  if (err==0) {
1803  sscanf(ctemp.Data(),"%d",&inter);
1804  if (inter >= 0) {
1805  inter += offset;
1806  actionCode = klandau + inter2;
1807  actionParam = inter;
1808  SetAction(fNoper,actionCode,actionParam);
1809  if (inter2 == 5) inter += 2;
1810  if (inter+3>fNpar) fNpar = inter+3;
1811  if (fNpar>=gMAXPAR) err=7; // too many parameters
1812  if (!err) fNoper++;
1813  if (fNpar == 3) SetNumber(400);
1814  } else err = 20; // non integer value for parameter number
1815  }
1816  } else if (err==0) {
1817  err=26; // unknown name
1818  chaine_error=chaine1ST;
1819  }
1820 
1821  // Look for a polynomial
1822 
1823  } else if (chaine(0,3) == "pol" || chaine(1,3) == "pol") {
1824  chaine1ST=chaine;
1825  if (chaine(1,3) == "pol") {
1826  ctemp=chaine(0,1);
1827  if (ctemp=="x") {
1828  inter2=1;
1829  if (fNdim < 1) fNdim = 1; }
1830  else if (ctemp=="y") {
1831  inter2=2;
1832  if (fNdim < 2) fNdim = 2; }
1833  else if (ctemp=="z") {
1834  inter2=3;
1835  if (fNdim < 3) fNdim = 3; }
1836  else if (ctemp=="t") {
1837  inter2=4;
1838  if (fNdim < 4) fNdim = 4; }
1839  else {
1840  err=26; // unknown name;
1841  chaine_error=chaine1ST;
1842  }
1843  chaine=chaine(1,lchain-1);
1844  lchain=chaine.Length();
1845  } else inter2=1;
1846  if (chaine(lchain-1,1) == ")") {
1847  nomb = 0;
1848  for (j=3;j<lchain;j++) if (chaine(j,1)=="(" && nomb == 0) nomb = j;
1849  if (nomb == 3) err = 23; // degree of polynomial not specified
1850  if (nomb == 0) err = 40; // '(' is expected
1851  ctemp = chaine(nomb+1,lchain-nomb-2);
1852  for (j=0; j<ctemp.Length(); j++) {
1853  t=ctemp[j];
1854  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1855  err=20;
1856  chaine_error=chaine1ST;
1857  }
1858  }
1859  if (!err) {
1860  sscanf(ctemp.Data(),"%d",&inter);
1861  if (inter < 0) err = 20;
1862  }
1863  }
1864  else {
1865  nomb = lchain;
1866  inter = 0;
1867  }
1868  if (!err) {
1869  inter--;
1870  ctemp = chaine(3,nomb-3);
1871  if (sscanf(ctemp.Data(),"%d",&n) > 0) {
1872  if (n < 0 ) err = 24; //Degree of polynomial must be positive
1873  if (n >= 20) err = 25; //Degree of polynomial must be less than 20
1874  } else err = 20;
1875  }
1876  if (!err) {
1877  fExpr[fNoper] = chaine1ST;
1878  actionCode = kpol+(inter2-1);
1879  actionParam = n*100+inter+2;
1880  SetAction(fNoper,actionCode,actionParam);
1881  if (inter+n+1>=fNpar) fNpar = inter + n + 2;
1882  if (fNpar>=gMAXPAR) err=7; // too many parameters
1883  if (!err) {
1884  fNoper++;
1885  if (fNdim < 1) fNdim = 1;
1886  SetNumber(300+n);
1887  }
1888  }
1889 
1890  // Look for pow,atan2,etc
1891 
1892  } else if (chaine(0,4) == "pow(") {
1893  compt = 4; nomb = 0; virgule = 0; nest=0;
1894  while(compt != lchain) {
1895  compt++;
1896  if (chaine(compt-1,1) == "(") nest++;
1897  else if (chaine(compt-1,1) == ")") nest--;
1898  else if (chaine(compt-1,1) == "," && nest==0) {
1899  nomb++;
1900  if (nomb == 1 && virgule == 0) virgule = compt;
1901  }
1902  }
1903  if (nomb != 1) err = 22; // There are plus or minus than 2 arguments for pow
1904  else {
1905  ctemp = chaine(4,virgule-5);
1906  Analyze(ctemp.Data(),err,offset); if (err) return;
1907  UInt_t leftopr = fNoper-1;
1908  ctemp = chaine(virgule,lchain-virgule-1);
1909  Analyze(ctemp.Data(),err,offset); if (err) return;
1910  fExpr[fNoper] = "^";
1911  actionCode = kpow;
1912  SetAction(fNoper,actionCode,actionParam);
1913  fNoper++;
1914  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1915  }
1916  } else if (chaine(0,7) == "strstr(") {
1917  compt = 7; nomb = 0; virgule = 0; nest=0;
1918  inString = false;
1919  while(compt != lchain) {
1920  compt++;
1921  if (chaine(compt-1,1) == "\"") {
1922  inString = !inString;
1923  } else if (!inString) {
1924  if (chaine(compt-1,1) == "(") nest++;
1925  else if (chaine(compt-1,1) == ")") nest--;
1926  else if (chaine(compt-1,1) == "," && nest==0) {
1927  nomb++;
1928  if (nomb == 1 && virgule == 0) virgule = compt;
1929  }
1930  }
1931  }
1932  if (nomb != 1) err = 28; // There are plus or minus than 2 arguments for strstr
1933  else {
1934  ctemp = chaine(7,virgule-8);
1935  Analyze(ctemp.Data(),err,offset); if (err) return;
1936  Int_t optloc = fNoper-1;
1937 
1938  ctemp = chaine(virgule,lchain-virgule-1);
1939  Analyze(ctemp.Data(),err,offset); if (err) return;
1940  fExpr[fNoper] = "strstr";
1941  actionCode = kstrstr;
1942  SetAction(fNoper,actionCode,actionParam);
1943  fNoper++;
1944 
1945  if ( !IsString(optloc) || !IsString(fNoper-2) ) {
1946  err = 46;
1947  chaine_error = "strstr";
1948  }
1949  }
1950  } else if (chaine(0,4) == "min(") {
1951  compt = 4; nomb = 0; virgule = 0; nest=0;
1952  while(compt != lchain) {
1953  compt++;
1954  if (chaine(compt-1,1) == "(") nest++;
1955  else if (chaine(compt-1,1) == ")") nest--;
1956  else if (chaine(compt-1,1) == "," && nest==0) {
1957  nomb++;
1958  if (nomb == 1 && virgule == 0) virgule = compt;
1959  }
1960  }
1961  if (nomb != 1) {
1962  err = 44; // There are plus or minus than 2 arguments for min
1963  err_hint = 3;
1964  }
1965  else {
1966  ctemp = chaine(4,virgule-5);
1967  Analyze(ctemp.Data(),err,offset); if (err) return;
1968  UInt_t leftopr = fNoper-1;
1969  ctemp = chaine(virgule,lchain-virgule-1);
1970  Analyze(ctemp.Data(),err,offset); if (err) return;
1971  fExpr[fNoper] = "min";
1972  actionCode = kmin;
1973  SetAction(fNoper,actionCode,actionParam);
1974  fNoper++;
1975  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1976  }
1977  } else if (chaine(0,4) == "max(") {
1978  compt = 4; nomb = 0; virgule = 0; nest=0;
1979  while(compt != lchain) {
1980  compt++;
1981  if (chaine(compt-1,1) == "(") nest++;
1982  else if (chaine(compt-1,1) == ")") nest--;
1983  else if (chaine(compt-1,1) == "," && nest==0) {
1984  nomb++;
1985  if (nomb == 1 && virgule == 0) virgule = compt;
1986  }
1987  }
1988  if (nomb != 1) {
1989  err = 44; // There are plus or minus than 2 arguments for min
1990  err_hint = 3;
1991  }
1992  else {
1993  ctemp = chaine(4,virgule-5);
1994  Analyze(ctemp.Data(),err,offset); if (err) return;
1995  UInt_t leftopr = fNoper-1;
1996  ctemp = chaine(virgule,lchain-virgule-1);
1997  Analyze(ctemp.Data(),err,offset); if (err) return;
1998  fExpr[fNoper] = "max";
1999  actionCode = kmax;
2000  SetAction(fNoper,actionCode,actionParam);
2001  fNoper++;
2002  if (!CheckOperands(leftopr,fNoper-1,err)) return;
2003  }
2004 
2005  } else if (chaine(0,6) == "atan2(") {
2006  compt = 6; nomb = 0; virgule = 0; nest=0;
2007  while(compt != lchain) {
2008  compt++;
2009  if (chaine(compt-1,1) == "(") nest++;
2010  else if (chaine(compt-1,1) == ")") nest--;
2011  else if (chaine(compt-1,1) == "," && nest==0) {
2012  nomb++;
2013  if (nomb == 1 && virgule == 0) virgule = compt;
2014  }
2015  }
2016  if (nomb != 1) err = 21; //{ There are plus or minus than 2 arguments for atan2
2017  else {
2018  ctemp = chaine(6,virgule-7);
2019  Analyze(ctemp.Data(),err,offset); if (err) return;
2020  UInt_t leftopr = fNoper-1;
2021  ctemp = chaine(virgule,lchain-virgule-1);
2022  Analyze(ctemp.Data(),err,offset); if (err) return;
2023  fExpr[fNoper] = "atan2";
2024  actionCode = katan2;
2025  SetAction(fNoper,actionCode,actionParam);
2026  fNoper++;
2027  if (!CheckOperands(leftopr,fNoper-1,err)) return;
2028  }
2029  } else if (chaine(0,5) == "fmod(") {
2030  compt = 5; nomb = 0; virgule = 0; nest=0;
2031  while(compt != lchain) {
2032  compt++;
2033  if (chaine(compt-1,1) == "(") nest++;
2034  else if (chaine(compt-1,1) == ")") nest--;
2035  else if (chaine(compt-1,1) == "," && nest==0) {
2036  nomb++;
2037  if (nomb == 1 && virgule == 0) virgule = compt;
2038  }
2039  }
2040  if (nomb != 1) {
2041  err = 44; // There are plus or minus than 2 arguments for fmod
2042  err_hint = 4;
2043  }
2044  else {
2045  ctemp = chaine(5,virgule-6);
2046  Analyze(ctemp.Data(),err,offset); if (err) return;
2047  UInt_t leftopr = fNoper-1;
2048  ctemp = chaine(virgule,lchain-virgule-1);
2049  Analyze(ctemp.Data(),err,offset); if (err) return;
2050  fExpr[fNoper] = "fmod";
2051  actionCode = kfmod;
2052  SetAction(fNoper,actionCode,actionParam);
2053  fNoper++;
2054  if (!CheckOperands(leftopr,fNoper-1,err)) return;
2055  }
2056  } else if (AnalyzeFunction(chaine,err,offset) || err) { // The '||err' is to grab an error coming from AnalyzeFunction
2057  if (err) {
2058  chaine_error = chaine;
2059  } else {
2060  // We have a function call. Note that all the work was already,
2061  // eventually done in AnalyzeFunction
2062  //fprintf(stderr,"We found a foreign function in %s\n",chaine.Data());
2063  }
2064  } else if (chaine(0,1) == "[" && chaine(lchain-1,1) == "]") {
2065  fExpr[fNoper] = chaine;
2066  fNoper++;
2067  ctemp = chaine(1,lchain-2);
2068  for (j=0; j<ctemp.Length(); j++) {
2069  t=ctemp[j];
2070  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
2071  err=20;
2072  chaine_error=chaine1ST; // le numero ? de par[?] n'est pas un entier }
2073  }
2074  }
2075  if (!err) {
2076  sscanf(ctemp.Data(),"%d",&valeur);
2077  actionCode = kParameter;
2078  actionParam = offset + valeur;
2079  SetAction(fNoper-1, actionCode, actionParam);
2080  fExpr[fNoper-1] = "[";
2081  fExpr[fNoper-1] = (fExpr[fNoper-1] + (long int)(valeur+offset)) + "]";
2082  }
2083  } else if (chaine == "pi") {
2084  fExpr[fNoper] = "pi";
2085  actionCode = kpi;
2086  SetAction(fNoper,actionCode,actionParam);
2087  fNoper++;
2088  }
2089  else {
2090 
2091  // None of the above.
2092 
2093  err = 30;
2094  }
2095  }
2096  }
2097  }
2098  }
2099  }
2100  }
2101 
2102  // Overflows
2103  if (fNoper>=gMAXOP) err=6; // too many operators
2104 
2105  }
2106 
2107  // errors!
2108  if (err>1) {
2109  TString er = "";
2110  chaine_error = "\""+chaine_error+"\"";
2111  switch(err) {
2112  case 2 : er = " Invalid Floating Point Operation"; break;
2113  case 4 : er = " Empty String"; break;
2114  case 5 : er = " Invalid Syntax " + chaine_error; break;
2115  case 6 : er = " Too many operators !"; break;
2116  case 7 : er = " Too many parameters !"; break;
2117  case 10 : er = " z specified but not x and y"; break;
2118  case 11 : er = " z and y specified but not x"; break;
2119  case 12 : er = " y specified but not x"; break;
2120  case 13 : er = " z and x specified but not y"; break;
2121  case 20 : er = " Non integer value for parameter number : " + chaine_error; break;
2122  case 21 : er = " ATAN2 requires two arguments"; break;
2123  case 22 : er = " POW requires two arguments"; break;
2124  case 23 : er = " Degree of polynomial not specified"; break;
2125  case 24 : er = " Degree of polynomial must be positive"; break;
2126  case 25 : er = " Degree of polynomial must be less than 20"; break;
2127  case 26 : er = " Unknown name : " + chaine_error; break;
2128  case 27 : er = " Too many constants in expression"; break;
2129  case 28 : er = " strstr requires two arguments"; break;
2130  case 29 : er = " TFormula can only call interpreted and compiled functions that return a numerical type: " + chaine_error; break;
2131  case 30 : er = " Bad numerical expression : " + chaine_error; break;
2132  case 31 : er = " Part of the Variable " + chaine_error; er += " exists but some of it is not accessible or useable"; break;
2133  case 40 : er = " '(' is expected"; break;
2134  case 41 : er = " ')' is expected"; break;
2135  case 42 : er = " '[' is expected"; break;
2136  case 43 : er = " ']' is expected"; break;
2137  case 44 : er = " The function '" + chaine(0,err_hint) + "' requires two arguments."; break;
2138  case 45 : er = "The operator " + chaine_error + " requires a numerical operand."; break;
2139  case 46 : er = "Both operands of the operator " + chaine_error + " have to be either numbers or strings."; break;
2140  case 47 : er = chaine_error + " requires 2 string arguments"; break;
2141  }
2142  Error("Compile", "%s", er.Data());
2143  err=1;
2144  }
2145 
2146 }
2147 
2148 
2149 ////////////////////////////////////////////////////////////////////////////////
2150 /// Check whether the operand at 'oper-1' is compatible with the operation
2151 /// at 'oper'.
2152 
2153 Bool_t TFormula::CheckOperands(Int_t oper, Int_t &err)
2154 {
2155  if ( IsString(oper-1) && !StringToNumber(oper-1) ) {
2156  Error("Compile","\"%s\" requires a numerical operand.",fExpr[oper].Data());
2157  err = 45;
2158  return kFALSE;
2159  }
2160  return kTRUE;
2161 }
2162 
2163 
2164 ////////////////////////////////////////////////////////////////////////////////
2165 /// Check whether the operands at 'leftoper' and 'oper-1' are compatible with
2166 /// the operation at 'oper'.
2167 
2168 Bool_t TFormula::CheckOperands(Int_t leftoper, Int_t oper, Int_t &err)
2169 {
2170  if ( IsString(oper-1) || IsString(leftoper) ) {
2171  if (IsString(oper-1) && StringToNumber(oper-1)) {
2172  return kTRUE;
2173  }
2174  if (IsString(leftoper) && StringToNumber(leftoper)) {
2175  return kTRUE;
2176  }
2177  Error("Compile","\"%s\" requires two numerical operands.",fExpr[oper].Data());
2178  err = 46;
2179  return kFALSE;
2180  }
2181  return kTRUE;
2182 }
2183 
2184 
2185 ////////////////////////////////////////////////////////////////////////////////
2186 /// Try to 'demote' a string into an array bytes. If this is not possible,
2187 /// return false.
2188 
2189 Bool_t TFormula::StringToNumber(Int_t /* code */)
2190 {
2191  // In TFormula proper, we can not handle array of bytes ...
2192  return kFALSE;
2193 }
2194 
2195 
2196 ////////////////////////////////////////////////////////////////////////////////
2197 /// Resets the objects.
2198 ///
2199 /// Resets the object to its state before compilation.
2200 
2201 void TFormula::Clear(Option_t * /*option*/ )
2202 {
2203  ClearFormula();
2204 }
2205 
2206 
2207 ////////////////////////////////////////////////////////////////////////////////
2208 /// Resets the objects.
2209 ///
2210 /// Resets the object to its state before compilation.
2211 
2212 void TFormula::ClearFormula(Option_t * /*option*/ )
2213 {
2214  fNdim = 0;
2215  fNpar = 0;
2216  fNoper = 0;
2217  fNconst = 0;
2218  fNumber = 0;
2219  fNstring= 0;
2220  fNval = 0;
2221 
2222  if (fExpr) { delete [] fExpr; fExpr = 0;}
2223  if (fNames) { delete [] fNames; fNames = 0;}
2224  if (fOper) { delete [] fOper; fOper = 0;}
2225  if (fConst) { delete [] fConst; fConst = 0;}
2226  if (fParams) { delete [] fParams; fParams = 0;}
2227  fFunctions.Delete();
2228  fLinearParts.Delete();
2229  //
2230  //MI change
2231  if (fPredefined) { delete [] fPredefined; fPredefined = 0;}
2232  if (fOperOffset) { delete [] fOperOffset; fOperOffset = 0;}
2233  if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = 0;}
2234  if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = 0;}
2235  // should we also remove the object from the list?
2236  // gROOT->GetListOfFunctions()->Remove(this);
2237  // if we don't, what happens if it fails the new compilation?
2238 }
2239 
2240 namespace {
2241  template <class T>
2242  inline static void ResizeArrayIfAllocated(T*& oldArray, int newSize){
2243 
2244  // Don't do anything in this case.
2245  if (!oldArray || newSize <=0) return;
2246 
2247  T* newArray = new T[newSize];
2248  std::copy(oldArray, oldArray+newSize, newArray);
2249  delete [] oldArray;
2250  oldArray = newArray;
2251  }
2252 }
2253 
2254 ////////////////////////////////////////////////////////////////////////////////
2255 /// Compile expression already stored in fTitle.
2256 ///
2257 /// Loop on all subexpressions of formula stored in fTitle
2258 ///
2259 /// If you overload this member function, you also HAVE TO
2260 /// never call the constructor:
2261 ///
2262 /// TFormula::TFormula(const char *name,const char *expression)
2263 ///
2264 /// and write your own constructor
2265 ///
2266 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2267 ///
2268 /// which has to call the TFormula default constructor and whose implementation
2269 /// should be similar to the implementation of the normal TFormula constructor
2270 ///
2271 /// This is necessary because the normal TFormula constructor call indirectly
2272 /// the virtual member functions Analyze, DefaultString, DefaultValue
2273 /// and DefaultVariable.
2274 ///
2275 ///Begin_Html
2276 
2277 Int_t TFormula::Compile(const char *expression)
2278 {
2279  /*
2280  <img src="gif/compile.gif">
2281  */
2282  //End_Html
2283 
2284  Int_t i,j,lc,valeur,err;
2285  TString ctemp;
2286 
2287  ClearFormula();
2288 
2289  // If expression is not empty, take it, otherwise take the title
2290  if (strlen(expression)) SetTitle(expression);
2291 
2292  TString chaine = GetTitle();
2293 
2294  if (chaine.Contains(";")) {
2295  char *sctemp = new char[chaine.Length()+1];
2296  strlcpy(sctemp,chaine.Data(),chaine.Length()+1);
2297  char *semicol = (char*)strstr(sctemp,";");
2298  if (semicol) *semicol = 0;
2299  chaine = sctemp;
2300  delete [] sctemp;
2301  }
2302 
2303  // if the function is linear, process it and fill the array of linear parts
2304  if (TestBit(kLinear)){
2305  ProcessLinear(chaine);
2306  }
2307 
2308  // see static function SetMaxima to change the gMAX.. default values
2309  fExpr = new TString[gMAXOP];
2310  fConst = new Double_t[gMAXCONST];
2311  fParams = new Double_t[gMAXPAR];
2312  fNames = new TString[gMAXPAR];
2313  fOper = new Int_t[gMAXOP];
2314  for (i=0; i<gMAXPAR; i++) {
2315  fParams[i] = 0;
2316  fNames[i] = "";
2317  }
2318  for (i=0; i<gMAXOP; i++) {
2319  fExpr[i] = "";
2320  fOper[i] = 0;
2321  }
2322  for (i=0; i<gMAXCONST; i++)
2323  fConst[i] = 0;
2324 
2325  // Substitution of some operators to C++ style
2326  Bool_t inString = false;
2327  for (i=1; i<=chaine.Length(); i++) {
2328  lc =chaine.Length();
2329  if (chaine(i-1,1) == "\"") inString = !inString;
2330  if (inString) continue;
2331  if (chaine(i-1,2) == "**") {
2332  chaine = chaine(0,i-1) + "^" + chaine(i+1,lc-i-1);
2333  i=0;
2334  } else if (chaine(i-1,2) == "++") {
2335  chaine = chaine(0,i) + chaine(i+1,lc-i-1);
2336  i=0;
2337  } else if (chaine(i-1,2) == "+-" || chaine(i-1,2) == "-+") {
2338  chaine = chaine(0,i-1) + "-" + chaine(i+1,lc-i-1);
2339  i=0;
2340  } else if (chaine(i-1,2) == "--") {
2341  chaine = chaine(0,i-1) + "+" + chaine(i+1,lc-i-1);
2342  i=0;
2343  } else if (chaine(i-1,2) == "->") {
2344  chaine = chaine(0,i-1) + "." + chaine(i+1,lc-i-1);
2345  i=0;
2346  } else if (chaine(i-1,1) == "[") {
2347  for (j=1;j<=chaine.Length()-i;j++) {
2348  if (chaine(j+i-1,1) == "]" || j+i > chaine.Length()) break;
2349  }
2350  ctemp = chaine(i,j-1);
2351  valeur=0;
2352  sscanf(ctemp.Data(),"%d",&valeur);
2353  if (valeur >= fNpar) fNpar = valeur+1;
2354  } else if (chaine(i-1,1) == " ") {
2355  chaine = chaine(0,i-1)+chaine(i,lc-i);
2356  i=0;
2357  }
2358  }
2359  err = 0;
2360  Analyze((const char*)chaine,err);
2361 
2362  // if no parameters delete arrays fParams and fNames
2363  if (!fNpar) {
2364  delete [] fParams; fParams = 0;
2365  delete [] fNames; fNames = 0;
2366  }
2367 
2368  // if no errors, copy local parameters to formula objects
2369  if (!err) {
2370  if (fNdim <= 0) fNdim = 1;
2371  if (chaine.Length() > 4)
2372  {
2373  if ( GetNumber() != 400 &&
2374  GetNumber() != 410 &&
2375  GetNumber() != 110 )
2376  SetNumber(0);
2377  else if ( GetNumber() == 110 && chaine.Length() > 6 )
2378  SetNumber(0);
2379  else if ( GetNumber() == 410 && chaine.Length() > 8 )
2380  SetNumber(0);
2381  }
2382  // if formula is a gaussian, set parameter names
2383  if (GetNumber() == 100) {
2384  SetParName(0,"Constant");
2385  SetParName(1,"Mean");
2386  SetParName(2,"Sigma");
2387  }
2388  // if formula is a 2D gaussian, set parameter names
2389  if (GetNumber() == 110){
2390  SetParName(0,"Constant");
2391  SetParName(1,"MeanX");
2392  SetParName(2,"SigmaX");
2393  SetParName(3,"MeanY");
2394  SetParName(4,"SigmaY");
2395  }
2396  // if formula is an exponential, set parameter names
2397  if (GetNumber() == 200) {
2398  SetParName(0,"Constant");
2399  SetParName(1,"Slope");
2400  }
2401  // if formula is a polynome, set parameter names
2402  if (GetNumber() == 300+fNpar) {
2403  for (i=0;i<fNpar;i++) SetParName(i,Form("p%d",i));
2404  }
2405  // if formula is a landau, set parameter names
2406  if (GetNumber() == 400) {
2407  SetParName(0,"Constant");
2408  SetParName(1,"MPV");
2409  SetParName(2,"Sigma");
2410  }
2411  // if formula is a 2D landau, set parameter names
2412  if (GetNumber() == 410) {
2413  SetParName(0,"Constant");
2414  SetParName(1,"MPVX");
2415  SetParName(2,"SigmaX");
2416  SetParName(3,"MPVY");
2417  SetParName(4,"SigmaY");
2418  }
2419  }
2420 
2421  // Here we shrink the arrays allocated like this:
2422  // fExpr = new TString[gMAXOP];
2423  // fConst = new Double_t[gMAXCONST];
2424  // fParams = new Double_t[gMAXPAR];
2425  // fNames = new TString[gMAXPAR];
2426  // fOper = new Int_t[gMAXOP];
2427  // fParams and fNames may be already 0, so we have to check.
2428  if (!err){
2429  ResizeArrayIfAllocated(fExpr, fNoper);
2430  ResizeArrayIfAllocated(fConst, fNconst);
2431  ResizeArrayIfAllocated(fParams, fNpar);
2432  ResizeArrayIfAllocated(fNames, fNpar);
2433  ResizeArrayIfAllocated(fOper, fNoper);
2434  }
2435 
2436 
2437  if (err) { fNdim = 0; return 1; }
2438  // Convert(5);
2439  //
2440  //MI change
2441  if (!IsA()->GetBaseClass("TTreeFormula")) {
2442  Optimize();
2443  }
2444  //
2445  return 0;
2446 }
2447 
2448 
2449 ////////////////////////////////////////////////////////////////////////////////
2450 /// Copy this formula.
2451 
2452 void TFormula::Copy(TObject &obj) const
2453 {
2454  Int_t i;
2455  ((TFormula&)obj).ClearFormula();
2456  TNamed::Copy(obj);
2457  ((TFormula&)obj).fNdim = fNdim;
2458  ((TFormula&)obj).fNpar = fNpar;
2459  ((TFormula&)obj).fNoper = fNoper;
2460  ((TFormula&)obj).fNconst = fNconst;
2461  ((TFormula&)obj).fNumber = fNumber;
2462  ((TFormula&)obj).fNval = fNval;
2463  ((TFormula&)obj).fExpr = 0;
2464  ((TFormula&)obj).fConst = 0;
2465  ((TFormula&)obj).fParams = 0;
2466  ((TFormula&)obj).fNames = 0;
2467  if (fExpr && fNoper) {
2468  ((TFormula&)obj).fExpr = new TString[fNoper];
2469  for (i=0;i<fNoper;i++) ((TFormula&)obj).fExpr[i] = fExpr[i];
2470  }
2471  if (fOper && fNoper) {
2472  ((TFormula&)obj).fOper = new Int_t[fNoper];
2473  for (i=0;i<fNoper;i++) ((TFormula&)obj).fOper[i] = fOper[i];
2474  }
2475  if (fConst && fNconst) {
2476  ((TFormula&)obj).fConst = new Double_t[fNconst];
2477  for (i=0;i<fNconst;i++) ((TFormula&)obj).fConst[i] = fConst[i];
2478  }
2479  if (fParams && fNpar) {
2480  ((TFormula&)obj).fParams = new Double_t[fNpar];
2481  for (i=0;i<fNpar;i++) ((TFormula&)obj).fParams[i] = fParams[i];
2482  }
2483  if (fNames && fNpar) {
2484  ((TFormula&)obj).fNames = new TString[fNpar];
2485  for (i=0;i<fNpar;i++) ((TFormula&)obj).fNames[i] = fNames[i];
2486  }
2487 
2488  TIter next(&fFunctions);
2489  TObject *fobj;
2490  while ( (fobj = next()) ) {
2491  ((TFormula&)obj).fFunctions.Add( fobj->Clone() );
2492  }
2493  //
2494  // MI change
2495  //
2496  //
2497  if (fNoper) {
2498  if(fExprOptimized) {
2499  ((TFormula&)obj).fExprOptimized = new TString[fNoper];
2500  for (i=0;i<fNoper;i++) ((TFormula&)obj).fExprOptimized[i] = fExprOptimized[i];
2501  }
2502  if (fOperOptimized) {
2503  ((TFormula&)obj).fOperOptimized = new Int_t[fNoper];
2504  for (i=0;i<fNoper;i++) ((TFormula&)obj).fOperOptimized[i] = fOperOptimized[i];
2505  }
2506  if (fPredefined) {
2507  ((TFormula&)obj).fPredefined = new ROOT::v5::TFormulaPrimitive*[fNoper];
2508  for (i=0;i<fNoper;i++) {((TFormula&)obj).fPredefined[i] = fPredefined[i];}
2509  }
2510  if (fOperOffset) {
2511  ((TFormula&)obj).fOperOffset = new TOperOffset[fNoper];
2512  for (i=0;i<fNoper;i++) {((TFormula&)obj).fOperOffset[i] = fOperOffset[i];}
2513  }
2514  }
2515  ((TFormula&)obj).fNOperOptimized = fNOperOptimized;
2516  ((TFormula&)obj).fOptimal = fOptimal;
2517 
2518 }
2519 
2520 
2521 ////////////////////////////////////////////////////////////////////////////////
2522 /// Return address of string corresponding to special code.
2523 ///
2524 /// This member function is inactive in the TFormula class.
2525 /// It may be redefined in derived classes.
2526 ///
2527 /// If you overload this member function, you also HAVE TO
2528 /// never call the constructor:
2529 ///
2530 /// TFormula::TFormula(const char *name,const char *expression)
2531 ///
2532 /// and write your own constructor
2533 ///
2534 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2535 ///
2536 /// which has to call the TFormula default constructor and whose implementation
2537 /// should be similar to the implementation of the normal TFormula constructor
2538 ///
2539 /// This is necessary because the normal TFormula constructor call indirectly
2540 /// the virtual member functions Analyze, DefaultString, DefaultValue
2541 /// and DefaultVariable.
2542 
2543 char *TFormula::DefinedString(Int_t)
2544 {
2545  return 0;
2546 }
2547 
2548 
2549 ////////////////////////////////////////////////////////////////////////////////
2550 /// Return value corresponding to special code.
2551 ///
2552 /// This member function is inactive in the TFormula class.
2553 /// It may be redefined in derived classes.
2554 ///
2555 /// If you overload this member function, you also HAVE TO
2556 /// never call the constructor:
2557 ///
2558 /// TFormula::TFormula(const char *name,const char *expression)
2559 ///
2560 /// and write your own constructor
2561 ///
2562 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2563 ///
2564 /// which has to call the TFormula default constructor and whose implementation
2565 /// should be similar to the implementation of the normal TFormula constructor
2566 ///
2567 /// This is necessary because the normal TFormula constructor call indirectly
2568 /// the virtual member functions Analyze, DefaultString, DefaultValue
2569 /// and DefaultVariable.
2570 
2571 Double_t TFormula::DefinedValue(Int_t)
2572 {
2573  return 0;
2574 }
2575 
2576 
2577 ////////////////////////////////////////////////////////////////////////////////
2578 /// Check if expression is in the list of defined variables.
2579 ///
2580 /// This member function can be overloaded in derived classes
2581 ///
2582 /// If you overload this member function, you also HAVE TO
2583 /// never call the constructor:
2584 ///
2585 /// TFormula::TFormula(const char *name,const char *expression)
2586 ///
2587 /// and write your own constructor
2588 ///
2589 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2590 ///
2591 /// which has to call the TFormula default constructor and whose implementation
2592 /// should be similar to the implementation of the normal TFormula constructor
2593 ///
2594 /// This is necessary because the normal TFormula constructor call indirectly
2595 /// the virtual member functions Analyze, DefaultString, DefaultValue
2596 /// and DefaultVariable.
2597 ///
2598 /// The expected returns values are
2599 /// -2 : the name has been recognized but won't be usable
2600 /// -1 : the name has not been recognized
2601 /// >=0 : the name has been recognized, return the action parameter.
2602 
2603 Int_t TFormula::DefinedVariable(TString &chaine,Int_t &action)
2604 {
2605  action = kVariable;
2606  if (chaine == "x") {
2607  if (fNdim < 1) fNdim = 1;
2608  return 0;
2609  } else if (chaine == "y") {
2610  if (fNdim < 2) fNdim = 2;
2611  return 1;
2612  } else if (chaine == "z") {
2613  if (fNdim < 3) fNdim = 3;
2614  return 2;
2615  } else if (chaine == "t") {
2616  if (fNdim < 4) fNdim = 4;
2617  return 3;
2618  }
2619  // MI change
2620  // extended defined variable (MI)
2621  //
2622  if (chaine.Data()[0]=='x'){
2623  if (chaine.Data()[1]=='[' && chaine.Data()[3]==']'){
2624  const char ch0 = '0';
2625  Int_t dim = chaine.Data()[2]-ch0;
2626  if (dim<0) return -1;
2627  if (dim>9) return -1;
2628  if (fNdim<=dim) fNdim = dim+1;
2629  return dim;
2630  }
2631  if (chaine.Data()[1]=='[' && chaine.Data()[4]==']'){
2632  const char ch0 = '0';
2633  Int_t dim = (chaine.Data()[2]-ch0)*10+(chaine.Data()[3]-ch0);
2634  if (dim<0) return -1;
2635  if (dim>99) return -1;
2636  if (fNdim<=dim) fNdim = dim+1;
2637  return dim;
2638  }
2639  }
2640  return -1;
2641 }
2642 
2643 
2644 ////////////////////////////////////////////////////////////////////////////////
2645 /// Evaluate this formula.
2646 ///
2647 /// The current value of variables x,y,z,t is passed through x, y, z and t.
2648 /// The parameters used will be the ones in the array params if params is given
2649 /// otherwise parameters will be taken from the stored data members fParams
2650 
2652 {
2653  Double_t xx[4];
2654  xx[0] = x;
2655  xx[1] = y;
2656  xx[2] = z;
2657  xx[3] = t;
2658  return ((TFormula*)this)->EvalPar(xx);
2659 }
2660 
2661 
2662 ////////////////////////////////////////////////////////////////////////////////
2663 /// Evaluate this formula.
2664 ///
2665 /// The current value of variables x,y,z,t is passed through the pointer x.
2666 /// The parameters used will be the ones in the array params if params is given
2667 /// otherwise parameters will be taken from the stored data members fParams
2668 ///Begin_Html
2669 
2670 Double_t TFormula::EvalParOld(const Double_t *x, const Double_t *uparams)
2671 {
2672  /*
2673  <img src="gif/eval.gif">
2674  */
2675  //End_Html
2676 
2677  Int_t i,j;
2678  // coverity[uninit] the tab value of tab is guaranteed to be set properly by the control flow.
2679  Double_t tab[kMAXFOUND];
2680  const char *stringStack[gMAXSTRINGFOUND];
2681  Double_t param_calc[kMAXFOUND];
2682  char *string_calc[gMAXSTRINGFOUND];
2683  Int_t precalculated = 0;
2684  Int_t precalculated_str = 0;
2685  Double_t *params;
2686 
2687  if (uparams) {
2688  params = const_cast<Double_t*>(uparams);
2689  } else {
2690  params = fParams;
2691  }
2692  UInt_t pos = 0;
2693  UInt_t strpos = 0;
2694 
2695  for (i=0; i<fNoper; ++i) {
2696 
2697  const int oper = fOper[i];
2698  const int opcode = oper >> kTFOperShift;
2699 
2700  switch(opcode) {
2701 
2702  case kParameter : { pos++; tab[pos-1] = params[ oper & kTFOperMask ]; continue; }
2703  case kConstant : { pos++; tab[pos-1] = fConst[ oper & kTFOperMask ]; continue; }
2704  case kVariable : { pos++; tab[pos-1] = x[ oper & kTFOperMask ]; continue; }
2705  case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExpr[i].Data(); pos++; tab[pos-1] = 0; continue; }
2706 
2707  case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
2708  case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
2709  case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
2710  case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
2711  else tab[pos-1] /= tab[pos];
2712  continue;
2713  case kModulo : {pos--;
2714  Long64_t int1((Long64_t)tab[pos-1]);
2715  Long64_t int2((Long64_t)tab[pos]);
2716  tab[pos-1] = Double_t(int1%int2);
2717  continue;}
2718 
2719  case kcos : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
2720  case ksin : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
2721  case ktan : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
2722  else tab[pos-1] = TMath::Tan(tab[pos-1]);
2723  continue;
2724  case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
2725  else tab[pos-1] = TMath::ACos(tab[pos-1]);
2726  continue;
2727  case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
2728  else tab[pos-1] = TMath::ASin(tab[pos-1]);
2729  continue;
2730  case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
2731  case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
2732  case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
2733  case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
2734  else tab[pos-1] = TMath::TanH(tab[pos-1]);
2735  continue;
2736  case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} // indetermination
2737  else tab[pos-1] = TMath::ACosH(tab[pos-1]);
2738  continue;
2739  case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
2740  case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
2741  else tab[pos-1] = TMath::ATanH(tab[pos-1]);
2742  continue;
2743  case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
2744 
2745  case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
2746  case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
2747  case ksq : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
2748  case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
2749 
2750  case kstrstr : strpos -= 2; pos-=2; pos++;
2751  if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
2752  else tab[pos-1]=0;
2753  continue;
2754 
2755  case kmin : pos--; tab[pos-1] = TMath::Min(tab[pos-1],tab[pos]); continue;
2756  case kmax : pos--; tab[pos-1] = TMath::Max(tab[pos-1],tab[pos]); continue;
2757 
2758  case klog : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
2759  else {tab[pos-1] = 0;} //{indetermination }
2760  continue;
2761  case kexp : { Double_t dexp = tab[pos-1];
2762  if (dexp < -700) {tab[pos-1] = 0; continue;}
2763  if (dexp > 700) {tab[pos-1] = TMath::Exp(700); continue;}
2764  tab[pos-1] = TMath::Exp(dexp); continue; }
2765  case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
2766  else {tab[pos-1] = 0;} //{indetermination }
2767  continue;
2768 
2769  case kpi : pos++; tab[pos-1] = TMath::ACos(-1); continue;
2770 
2771  case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
2772  case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
2773  case kint : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
2774 
2775  case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
2776 
2777  case krndm : pos++; tab[pos-1] = gRandom->Rndm(1); continue;
2778 
2779  case kAnd : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
2780  else tab[pos-1]=0;
2781  continue;
2782  case kOr : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
2783  else tab[pos-1]=0;
2784  continue;
2785  case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
2786  else tab[pos-1]=0;
2787  continue;
2788  case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
2789  else tab[pos-1]=0;
2790  continue;
2791  case kLess : pos--; if (tab[pos-1] < tab[pos]) tab[pos-1]=1;
2792  else tab[pos-1]=0;
2793  continue;
2794  case kGreater : pos--; if (tab[pos-1] > tab[pos]) tab[pos-1]=1;
2795  else tab[pos-1]=0;
2796  continue;
2797 
2798  case kLessThan: pos--; if (tab[pos-1]<=tab[pos]) tab[pos-1]=1;
2799  else tab[pos-1]=0;
2800  continue;
2801  case kGreaterThan: pos--; if (tab[pos-1]>=tab[pos]) tab[pos-1]=1;
2802  else tab[pos-1]=0;
2803  continue;
2804  case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1;
2805  continue;
2806 
2807  case kStringEqual : strpos -= 2; pos -=2 ; pos++;
2808  if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
2809  else tab[pos-1]=0;
2810  continue;
2811  case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
2812  if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
2813  else tab[pos-1]=0;
2814  continue;
2815 
2816  case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
2817  case kBitOr : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
2818  case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
2819  case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
2820 
2821  case kJump : i = (oper & kTFOperMask); continue;
2822  case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
2823 
2824  case kBoolOptimize: {
2825  // boolean operation optimizer
2826 
2827  int param = (oper & kTFOperMask);
2828  Bool_t skip = kFALSE;
2829  int op = param % 10; // 1 is && , 2 is ||
2830 
2831  if (op == 1 && (!tab[pos-1]) ) {
2832  // &&: skip the right part if the left part is already false
2833 
2834  skip = kTRUE;
2835 
2836  // Preserve the existing behavior (i.e. the result of a&&b is
2837  // either 0 or 1)
2838  tab[pos-1] = 0;
2839 
2840  } else if (op == 2 && tab[pos-1] ) {
2841  // ||: skip the right part if the left part is already true
2842 
2843  skip = kTRUE;
2844 
2845  // Preserve the existing behavior (i.e. the result of a||b is
2846  // either 0 or 1)
2847  tab[pos-1] = 1;
2848 
2849  }
2850 
2851  if (skip) {
2852  int toskip = param / 10;
2853  i += toskip;
2854  }
2855  continue;
2856  }
2857 
2858  }
2859 
2860  switch(opcode) {
2861 
2862  #define R__EXPO(var) \
2863  { \
2864  pos++; int param = (oper & kTFOperMask); \
2865  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]); \
2866  continue; \
2867  }
2868  // case kexpo:
2869  case kxexpo: R__EXPO(0);
2870  case kyexpo: R__EXPO(1);
2871  case kzexpo: R__EXPO(2);
2872  case kxyexpo:{ pos++; int param = (oper & kTFOperMask);
2873  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
2874  continue; }
2875 
2876  #define R__GAUS(var) \
2877  { \
2878  pos++; int param = (oper & kTFOperMask); \
2879  tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1],params[param+2],IsNormalized()); \
2880  continue; \
2881  }
2882 
2883  // case kgaus:
2884  case kxgaus: R__GAUS(0);
2885  case kygaus: R__GAUS(1);
2886  case kzgaus: R__GAUS(2);
2887  case kxygaus: {pos++; int param = (oper & kTFOperMask);
2888  Double_t intermede1;
2889  if (params[param+2] == 0) {
2890  intermede1=1e10;
2891  } else {
2892  intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
2893  }
2894  Double_t intermede2;
2895  if (params[param+4] == 0) {
2896  intermede2=1e10;
2897  } else {
2898  intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
2899  }
2900  tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
2901  continue; }
2902 
2903  #define R__LANDAU(var) \
2904  { \
2905  pos++; const int param = (oper & kTFOperMask); \
2906  tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
2907  continue; \
2908  }
2909  // case klandau:
2910  case kxlandau: R__LANDAU(0);
2911  case kylandau: R__LANDAU(1);
2912  case kzlandau: R__LANDAU(2);
2913  case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
2914  Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
2915  Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
2916  tab[pos-1] = params[param]*intermede1*intermede2;
2917  continue;
2918  }
2919 
2920  #define R__POLY(var) \
2921  { \
2922  pos++; int param = (oper & kTFOperMask); \
2923  tab[pos-1] = 0; Double_t intermede = 1; \
2924  Int_t inter = param/100; /* arrondit */ \
2925  Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
2926  for (j=0 ;j<inter+1;j++) { \
2927  tab[pos-1] += intermede*params[j+int1]; \
2928  intermede *= x[var]; \
2929  } \
2930  continue; \
2931  }
2932  // case kpol:
2933  case kxpol: R__POLY(0);
2934  case kypol: R__POLY(1);
2935  case kzpol: R__POLY(2);
2936 
2937  case kDefinedVariable : {
2938  if (!precalculated) {
2939  precalculated = 1;
2940  for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
2941  }
2942  pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
2943  continue;
2944  }
2945 
2946  case kDefinedString : {
2947  int param = (oper & kTFOperMask);
2948  if (!precalculated_str) {
2949  precalculated_str=1;
2950  for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
2951  }
2952  strpos++; stringStack[strpos-1] = string_calc[param];
2953  pos++; tab[pos-1] = 0;
2954  continue;
2955  }
2956 
2957  case kFunctionCall: {
2958  // an external function call
2959 
2960  int param = (oper & kTFOperMask);
2961  int fno = param / 1000;
2962  int nargs = param % 1000;
2963 
2964  // Retrieve the function
2965  TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
2966 
2967  // Set the arguments
2968  method->ResetParam();
2969  if (nargs) {
2970  UInt_t argloc = pos-nargs;
2971  for(j=0;j<nargs;j++,argloc++,pos--) {
2972  method->SetParam(tab[argloc]);
2973  }
2974  }
2975  pos++;
2976  Double_t ret;
2977  method->Execute(ret);
2978  tab[pos-1] = ret; // check for the correct conversion!
2979 
2980  continue;
2981  };
2982  }
2983  if (!TestBit(kOptimizationError)) {
2984  SetBit(kOptimizationError);
2985  Warning("EvalParOld","Found an unsupported opcode (%d)",oper >> kTFOperShift);
2986  }
2987  }
2988  Double_t result0 = tab[0];
2989  return result0;
2990 
2991 }
2992 
2993 ////////////////////////////////////////////////////////////////////////////////
2994 /// Reconstruct the formula expression from the internal TFormula member variables
2995 ///
2996 /// This function uses the internal member variables of TFormula to
2997 /// construct the mathematical expression associated with the TFormula
2998 /// instance. This function can be used to get an expanded version of the
2999 /// expression originally assigned to the TFormula instance, i.e. that
3000 /// the string returned by GetExpFormula() doesn't depend on other
3001 /// TFormula object names.
3002 ///
3003 /// if option contains "p" the returned string will contain the formula
3004 /// expression with symbolic parameters, eg [0] replaced by the actual value
3005 /// of the parameter. Example:
3006 /// if expression in formula is: "[0]*(x>-[1])+[2]*exp(-[3]*x)"
3007 /// and parameters are 3.25,-4.01,4.44,-0.04, GetExpFormula("p") will return:
3008 /// "(3.25*(x>+4.01))+(4.44*exp(+0.04*x))"
3009 
3011 {
3012  if (fNoper>0) {
3013  TString* tab=new TString[fNoper];
3014  Bool_t* ismulti=new Bool_t[fNoper];
3015  Int_t spos=0;
3016 
3017  ismulti[0]=kFALSE;
3018  Int_t optype;
3019  Int_t j;
3020  Int_t ternaryend = -1;
3021  for(Int_t i=0;i<fNoper;i++){
3022  optype = GetAction(i);
3023 
3024  if (ternaryend==i) {
3025  // The ? and : have been added to tab[spos-2]
3026  if(ismulti[spos-1]){
3027  tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
3028  } else {
3029  tab[spos-2]=tab[spos-2]+tab[spos-1];
3030  }
3031  spos--;
3032  // Do not call continue since we need to
3033  // do the rest of the loop.
3034  }
3035 
3036  // Boolean optimization breakpoint
3037  if (optype==kBoolOptimize) { // -3) {
3038  continue;
3039  }
3040 
3041  //Sign inversion
3042  if (optype==kSignInv) { // -1) {
3043  tab[spos-1]="-("+tab[spos-1]+")";
3044  // i++;
3045  continue;
3046  }
3047 
3048  //Simple name (parameter,pol0,landau, etc)
3049  if (kexpo<=optype && optype<=kzpol) { // >=0) {
3050  tab[spos]=fExpr[i];
3051  ismulti[spos]=kFALSE;
3052  spos++;
3053  continue;
3054  }
3055 
3056  //constants, variables x,y,z,t, pi
3057  if ((optype<=151 && optype>=140 && optype!=145) || (optype == 40)) {
3058  tab[spos]=fExpr[i];
3059  ismulti[spos]=kFALSE;
3060  spos++;
3061  continue;
3062  }
3063 
3064  //Basic operators (+,-,*,/,==,^,etc)
3065  if(((optype>0 && optype<6) || optype==20 ||
3066  (((optype>59 && optype<69) || (optype >75 && optype<82)) && spos>=2))) {
3067  // if(optype==-20 && spos>=2){
3068  if(ismulti[spos-2]){
3069  tab[spos-2]="("+tab[spos-2]+")";
3070  }
3071  if(ismulti[spos-1]){
3072  tab[spos-2]+=fExpr[i]+("("+tab[spos-1]+")");
3073  }else{
3074  tab[spos-2]+=fExpr[i]+tab[spos-1];
3075  }
3076  ismulti[spos-2]=kTRUE;
3077  spos--;
3078  continue;
3079  }
3080  //Ternary condition
3081  if (optype==kJumpIf) {
3082  if(ismulti[spos-1]){
3083  tab[spos-1]="("+tab[spos-1]+")?";
3084  } else {
3085  tab[spos-1]=tab[spos-1]+"?";
3086  }
3087  continue;
3088  }
3089  if (optype==kJump) {
3090  if(ismulti[spos-1]){
3091  tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+"):";
3092  } else {
3093  tab[spos-2]=tab[spos-2]+tab[spos-1]+":";
3094  }
3095  ternaryend = GetActionParam(i) + 1;
3096  spos--;
3097  continue;
3098  }
3099 
3100  //Functions
3101  int offset = 0;
3102  TString funcname = fExpr[i];
3103  if((optype>9 && optype<16) ||
3104  (optype>20 && optype<23) ||
3105  (optype>29 && optype<34) ||
3106  (optype>40 && optype<44) ||
3107  (optype>69 && optype<76) ||
3108  (optype==145)) {
3109  //Functions with the format func(x)
3110  offset = -1;
3111  }
3112 
3113  if((optype>15 && optype<20) ||
3114  (optype>22 && optype<26)) {
3115  //Functions with the format func(x,y)
3116  offset = -2;
3117  }
3118  if(optype==145) {
3119  int param = (fOper[i] & kTFOperMask);
3120  //int fno = param / 1000;
3121  int nargs = param % 1000;
3122  offset = -nargs;
3123  // The function name contains return type and parameters types we need
3124  // to trim them.
3125  int depth;
3126  for(j=0, depth=0;j<funcname.Length();++j) {
3127  switch (funcname[j]) {
3128  case '<':
3129  ++depth; break;
3130  case '>':
3131  --depth; break;
3132  case ' ':
3133  if (depth==0) {
3134  funcname.Remove(0,j+1);
3135  j = funcname.Length();
3136  break;
3137  }
3138  }
3139  }
3140  Ssiz_t ind = funcname.First('(');
3141  funcname.Remove(ind);
3142  }
3143  if (offset > 0) {
3144  Error("GetExpFormula","Internal error, number of argument found is %d",-offset);
3145  } else if (offset == 0) {
3146  tab[spos]=funcname+"()";
3147  ismulti[spos]=kFALSE;
3148  spos += 1;
3149  continue;
3150  } else if (offset<=0 && (spos+offset>=0)) {
3151  tab[spos+offset]=funcname+("("+tab[spos+offset]);
3152  for (j=offset+1; j<0; j++){
3153  tab[spos+offset]+=","+tab[spos+j];
3154  }
3155  tab[spos+offset]+=")";
3156  ismulti[spos+offset]=kFALSE;
3157  spos += offset+1;
3158  continue;
3159  }
3160  }
3161  if (ternaryend==fNoper) {
3162  // The ? and : have been added to tab[spos-2]
3163  if(ismulti[spos-1]){
3164  tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
3165  } else {
3166  tab[spos-2]=tab[spos-2]+tab[spos-1];
3167  }
3168  spos--;
3169  }
3170 
3171  TString ret = "";
3172  if (spos > 0) ret = tab[spos-1];
3173  delete[] tab;
3174  delete[] ismulti;
3175 
3176  //if option "p" is specified, return the real values of parameters instead of [0]
3177  TString opt = option;
3178  opt.ToLower();
3179  if (opt.Contains("p")) {
3180  char pb[10];
3181  char pbv[100];
3182  for (j=0;j<fNpar;j++) {
3183  snprintf(pb,10,"[%d]",j);
3184  snprintf(pbv,100,"%g",fParams[j]);
3185  ret.ReplaceAll(pb,pbv);
3186  }
3187  ret.ReplaceAll("--","+");
3188  ret.ReplaceAll("+-","-");
3189  }
3190  return ret;
3191  } else{
3192  TString ret="";
3193  return ret;
3194  }
3195 }
3196 
3197 
3198 ////////////////////////////////////////////////////////////////////////////////
3199 /// Return linear part.
3200 
3202 {
3203  if (!fLinearParts.IsEmpty())
3204  return fLinearParts.UncheckedAt(i);
3205  return 0;
3206 }
3207 
3208 
3209 ////////////////////////////////////////////////////////////////////////////////
3210 /// Return value of parameter number ipar.
3211 
3213 {
3214  if (ipar <0 || ipar >= fNpar) return 0;
3215  return fParams[ipar];
3216 }
3217 
3218 
3219 ////////////////////////////////////////////////////////////////////////////////
3220 /// Return value of parameter named parName.
3221 
3222 Double_t TFormula::GetParameter(const char *parName) const
3223 {
3224  const Double_t kNaN = 1e-300;
3225  Int_t index = GetParNumber(parName);
3226  if (index==-1) {
3227  Error("TFormula", "Parameter %s not found", parName);
3228  return kNaN;
3229  }
3230  return GetParameter(index);
3231 }
3232 
3233 
3234 ////////////////////////////////////////////////////////////////////////////////
3235 /// Return name of one parameter.
3236 
3237 const char *TFormula::GetParName(Int_t ipar) const
3238 {
3239  if (ipar <0 || ipar >= fNpar) return "";
3240  if (fNames[ipar].Length() > 0) return (const char*)fNames[ipar];
3241  return Form("p%d",ipar);
3242 }
3243 
3244 
3245 ////////////////////////////////////////////////////////////////////////////////
3246 /// Return parameter number by name.
3247 
3248 Int_t TFormula::GetParNumber(const char *parName) const
3249 {
3250  if (!parName)
3251  return -1;
3252 
3253  for (Int_t i=0; i<fNpar; i++) {
3254  if (!strcmp(GetParName(i),parName)) return i;
3255  }
3256  return -1;
3257 }
3258 
3259 
3260 ////////////////////////////////////////////////////////////////////////////////
3261 /// Return true if the expression at the index 'oper' has to be treated as a string
3262 
3263 Bool_t TFormula::IsString(Int_t oper) const
3264 {
3265  return GetAction(oper) == kStringConst;
3266 }
3267 
3268 
3269 ////////////////////////////////////////////////////////////////////////////////
3270 /// Dump this formula with its attributes.
3271 
3272 void TFormula::Print(Option_t *) const
3273 {
3274  Int_t i;
3275  Printf(" %20s : %s Ndim= %d, Npar= %d, Noper= %d",GetName(),GetTitle(), fNdim,fNpar,fNoper);
3276  for (i=0;i<fNoper;i++) {
3277  Printf(" fExpr[%d] = %s action = %d action param = %d ",
3278  i,(const char*)fExpr[i],GetAction(i),GetActionParam(i));
3279  }
3280  //MI change
3281  //
3282  if (fNOperOptimized>0){
3283  Printf("Optimized expression");
3284  for (i=0;i<fNOperOptimized;i++) {
3285  Printf(" fExpr[%d] = %s\t\t action = %d action param = %d ",
3286  i,(const char*)fExprOptimized[i],GetActionOptimized(i),GetActionParamOptimized(i));
3287  }
3288  }
3289 
3290  if (!fNames) return;
3291  if (!fParams) return;
3292  for (i=0;i<fNpar;i++) {
3293  Printf(" Par%3d %20s = %g",i,GetParName(i),fParams[i]);
3294  }
3295 }
3296 
3297 
3298 ////////////////////////////////////////////////////////////////////////////////
3299 /// If the formula is for linear fitting, change the title to
3300 /// normal and fill the LinearParts array
3301 
3302 void TFormula::ProcessLinear(TString &formula)
3303 {
3304  TString formula2(formula);
3305  char repl[20];
3306  char *pch;
3307  Int_t nf, offset, replsize;
3308  //replace "++" with "+[i]*"
3309  pch= (char*)strstr(formula.Data(), "++");
3310  if (pch)
3311  formula.Insert(0, "[0]*(");
3312  pch= (char*)strstr(formula.Data(), "++");
3313  if (pch){
3314  //if there are "++", replaces them with +[i]*
3315  nf = 1;
3316  while (pch){
3317  snprintf(repl,20, ")+[%d]*(", nf);
3318  offset = pch-formula.Data();
3319  if (nf<10) replsize = 7;
3320  else if (nf<100) replsize = 8;
3321  else replsize = 9;
3322  formula.Replace(pch-formula.Data(), 2, repl, replsize);
3323  pch = (char*)strstr(formula.Data()+offset, "++");
3324  nf++;
3325  }
3326  formula.Append(')', 1);
3327  } else {
3328  //if there are no ++, create a new string with ++ instead of +[i]*
3329  formula2=formula2(4, formula2.Length()-4);
3330  pch= (char*)strchr(formula2.Data(), '[');
3331  snprintf(repl,20, "++");
3332  nf = 1;
3333  while (pch){
3334  offset = pch-formula2.Data()-1;
3335  if (nf<10) replsize = 5;
3336  else replsize = 6;
3337  formula2.Replace(pch-formula2.Data()-1, replsize, repl, 2);
3338  pch = (char*)strchr(formula2.Data()+offset, '[');
3339  nf++;
3340  }
3341  }
3342 
3343  fLinearParts.Expand(nf);
3344  //break up the formula and fill the array of linear parts
3345  TString replaceformula;
3346  formula2 = formula2.ReplaceAll("++", 2, "|", 1);
3347  TObjArray *oa = formula2.Tokenize("|");
3348  TString replaceformula_name;
3349  for (Int_t i=0; i<nf; i++) {
3350  replaceformula = ((TObjString *)oa->UncheckedAt(i))->GetString();
3351  replaceformula_name = "f_linear_";
3352  replaceformula_name.Append(replaceformula);
3353  TFormula *f = new TFormula(replaceformula_name.Data(), replaceformula.Data());
3354  if (!f) {
3355  Error("TFormula", "f_linear not allocated");
3356  return;
3357  }
3358  {
3360  gROOT->GetListOfFunctions()->Remove(f);
3361  }
3362  f->SetBit(kNotGlobal, 1);
3363  fLinearParts.Add(f);
3364  }
3365  oa->Delete();
3366 }
3367 
3368 
3369 ////////////////////////////////////////////////////////////////////////////////
3370 /// Initialize parameter number ipar.
3371 
3372 void TFormula::SetParameter(const char *name, Double_t value)
3373 {
3374  Int_t ipar = GetParNumber(name);
3375  if (ipar <0 || ipar >= fNpar) return;
3376  fParams[ipar] = value;
3377  Update();
3378 }
3379 
3380 
3381 ////////////////////////////////////////////////////////////////////////////////
3382 /// Initialize parameter number ipar.
3383 
3384 void TFormula::SetParameter(Int_t ipar, Double_t value)
3385 {
3386  if (ipar <0 || ipar >= fNpar) return;
3387  fParams[ipar] = value;
3388  Update();
3389 }
3390 
3391 
3392 ////////////////////////////////////////////////////////////////////////////////
3393 /// Initialize array of all parameters.
3394 /// See also the next function with the same name.
3395 
3396 void TFormula::SetParameters(const Double_t *params)
3397 {
3398  for (Int_t i=0; i<fNpar;i++) {
3399  fParams[i] = params[i];
3400  }
3401  Update();
3402 }
3403 
3404 
3405 ////////////////////////////////////////////////////////////////////////////////
3406 /// Initialize up to 11 parameters
3407 /// All arguments except THE FIRST TWO are optional
3408 /// In case of a function with only one parameter, call this function with p1=0.
3409 /// Minimum two arguments are required to differentiate this function
3410 /// from the SetParameters(cont Double_t *params)
3411 
3413  ,Double_t p5,Double_t p6,Double_t p7,Double_t p8,Double_t p9,Double_t p10)
3414 {
3415  if (fNpar > 0) fParams[0] = p0;
3416  if (fNpar > 1) fParams[1] = p1;
3417  if (fNpar > 2) fParams[2] = p2;
3418  if (fNpar > 3) fParams[3] = p3;
3419  if (fNpar > 4) fParams[4] = p4;
3420  if (fNpar > 5) fParams[5] = p5;
3421  if (fNpar > 6) fParams[6] = p6;
3422  if (fNpar > 7) fParams[7] = p7;
3423  if (fNpar > 8) fParams[8] = p8;
3424  if (fNpar > 9) fParams[9] = p9;
3425  if (fNpar >10) fParams[10]= p10;
3426  Update();
3427 }
3428 
3429 
3430 ////////////////////////////////////////////////////////////////////////////////
3431 /// Set name of parameter number ipar
3432 
3433 void TFormula::SetParName(Int_t ipar, const char *name)
3434 {
3435  if (ipar <0 || ipar >= fNpar) return;
3436  fNames[ipar] = name;
3437 }
3438 
3439 
3440 ////////////////////////////////////////////////////////////////////////////////
3441 /// Set up to 11 parameter names.
3442 
3443 void TFormula::SetParNames(const char*name0,const char*name1,const char*name2,const char*name3,const char*name4,
3444  const char*name5,const char*name6,const char*name7,const char*name8,const char*name9,const char*name10)
3445 {
3446  if (fNpar > 0) fNames[0] = name0;
3447  if (fNpar > 1) fNames[1] = name1;
3448  if (fNpar > 2) fNames[2] = name2;
3449  if (fNpar > 3) fNames[3] = name3;
3450  if (fNpar > 4) fNames[4] = name4;
3451  if (fNpar > 5) fNames[5] = name5;
3452  if (fNpar > 6) fNames[6] = name6;
3453  if (fNpar > 7) fNames[7] = name7;
3454  if (fNpar > 8) fNames[8] = name8;
3455  if (fNpar > 9) fNames[9] = name9;
3456  if (fNpar >10) fNames[10]= name10;
3457 }
3458 
3459 ////////////////////////////////////////////////////////////////////////////////
3460 /// Stream a class object.
3461 
3462 void TFormula::Streamer(TBuffer &b, const TClass *onfile_class)
3463 {
3464  if (b.IsReading()) {
3465  UInt_t R__s, R__c;
3466  Version_t v = b.ReadVersion(&R__s, &R__c);
3467  if (v==6) {
3468  Error("Streamer","version 6 is not supported");
3469  return;
3470  }
3471  Streamer(b, v, R__s, R__c, onfile_class);
3472 
3473  } else {
3475  }
3476 }
3477 
3478 ////////////////////////////////////////////////////////////////////////////////
3479 /// Stream a class object.
3480 
3481 void TFormula::Streamer(TBuffer &b)
3482 {
3483  if (b.IsReading()) {
3484  UInt_t R__s, R__c;
3485  Version_t v = b.ReadVersion(&R__s, &R__c);
3486  if (v==6) {
3487  Error("Streamer","version 6 is not supported");
3488  return;
3489  }
3490  Streamer(b, v, R__s, R__c, nullptr);
3491 
3492  } else {
3494  }
3495 }
3496 
3497 ////////////////////////////////////////////////////////////////////////////////
3498 /// specialized streamer function being able to read old TF1 versions as TF1Old in memory
3499 
3500 void TFormula::Streamer(TBuffer &b, Int_t v, UInt_t R__s, UInt_t R__c, const TClass *onfile_class)
3501 {
3502 
3503  //printf("Reading TFormula - version %d \n",v);
3504  if (v > 3 ) {
3505  b.ReadClassBuffer(TFormula::Class(), this, v, R__s, R__c, onfile_class);
3506  if (!TestBit(kNotGlobal)) {
3508  gROOT->GetListOfFunctions()->Add(this);
3509  }
3510 
3511  // We need to reinstate (if possible) the TMethodCall.
3512  if (fFunctions.GetLast()>=0) {
3513  // Compiles will reset the parameter values so we need
3514  // to temporarily keep them
3515  Double_t *param = fParams;
3516  TString *names = fNames;
3517  Int_t npar = fNpar;
3518  fParams = 0;
3519  fNames = 0;
3520  if (Compile()) {
3521  Error("Streamer","error compiling formula");
3522  return;
3523  }
3524  for (Int_t i = 0; i<npar && i<fNpar; ++i) fParams[i] = param[i];
3525  delete [] param;
3526  delete [] fNames;
3527  fNames = names;
3528  } else if (v<6) {
3529  Convert(v);
3530  }
3531  Optimize();
3532  return;
3533  }
3534  // version smaller or equal to 3
3535  // process old versions before automatic schema evolution
3536  TNamed::Streamer(b);
3537  b >> fNdim;
3538  b >> fNumber;
3539  if (v > 1) b >> fNval;
3540  if (v > 2) b >> fNstring;
3541  fNpar = b.ReadArray(fParams);
3542  fOper = new Int_t[gMAXOP];
3543  fNoper = b.ReadArray(fOper);
3544  fNconst = b.ReadArray(fConst);
3545  if (fNoper) {
3546  fExpr = new TString[fNoper];
3547  }
3548  if (fNpar) {
3549  fNames = new TString[fNpar];
3550  }
3551  Int_t i;
3552  for (i=0;i<fNoper;i++) fExpr[i].Streamer(b);
3553  for (i=0;i<fNpar;i++) fNames[i].Streamer(b);
3554  {
3556  if (gROOT->GetListOfFunctions()->FindObject(GetName())) return;
3557  gROOT->GetListOfFunctions()->Add(this);
3558  }
3559  b.CheckByteCount(R__s, R__c, TFormula::IsA());
3560 
3561  Convert(v);
3562  // end of old versions
3563 
3564 }
3565 
3566 void TFormula::Convert(UInt_t /* fromVersion */)
3567 {
3568  // Convert the fOper of a TFormula version fromVersion to the current in memory version
3569 
3570  enum {
3571  kOldexpo = 1000,
3572  kOldgaus = 2000,
3573  kOldlandau = 4000,
3574  kOldxylandau = 4500,
3575  kOldConstants = 50000,
3576  kOldStrings = 80000,
3577  kOldVariable = 100000,
3578  kOldTreeString = 105000,
3579  kOldFormulaVar = 110000,
3580  kOldBoolOptimize = 120000,
3581  kOldFunctionCall = 200000
3582  };
3583  int i,j;
3584 
3585  for (i=0,j=0; i<fNoper; ++i,++j) {
3586  Int_t action = fOper[i];
3587  Int_t newActionCode = 0;
3588  Int_t newActionParam = 0;
3589 
3590  if ( action == 0) {
3591  // Sign Inversion
3592 
3593  newActionCode = kSignInv;
3594 
3595  Float_t aresult = 99.99;
3596  sscanf((const char*)fExpr[i],"%g",&aresult);
3597  R__ASSERT((aresult+1)<0.001);
3598 
3599  ++i; // skip the implied multiplication.
3600 
3601  // For consistency and for Optimize to work correctly
3602  // we need to remove the "-1" string in fExpr
3603  for (int z=i; z<fNoper; ++z) {
3604  fExpr[z-1] = fExpr[z];
3605  }
3606 
3607  } else if ( action < 100 ) {
3608  // basic operators and mathematical library
3609 
3610  newActionCode = action;
3611 
3612  } else if (action >= kOldFunctionCall) {
3613  // Function call
3614 
3615  newActionCode = kFunctionCall;
3616  newActionParam = action-kOldFunctionCall;
3617 
3618  } else if (action >= kOldBoolOptimize) {
3619  // boolean operation optimizer
3620 
3621  newActionCode = kBoolOptimize;
3622  newActionParam = action-kOldBoolOptimize;
3623 
3624  } else if (action >= kOldFormulaVar) {
3625  // a variable
3626 
3627  newActionCode = kVariable;
3628  newActionParam = action-kOldFormulaVar;
3629 
3630  } else if (action >= kOldTreeString) {
3631  // a tree string
3632 
3633  newActionCode = kDefinedString;
3634  newActionParam = action-kOldTreeString;
3635 
3636  } else if (action >= kOldVariable) {
3637  // a tree variable
3638 
3639  newActionCode = kDefinedVariable;
3640  newActionParam = action-kOldVariable;
3641 
3642  } else if (action == kOldStrings) {
3643  // String
3644 
3645  newActionCode = kStringConst;
3646 
3647  } else if (action >= kOldConstants) {
3648  // numerical value
3649 
3650  newActionCode = kConstant;
3651  newActionParam = action-kOldConstants;
3652 
3653  } else if (action > 10000 && action < kOldConstants) {
3654  // Polynomial
3655 
3656  int var = action/10000; //arrondit
3657  newActionCode = kpol + (var-1);
3658  newActionParam = action - var*10000;
3659 
3660  } else if (action >= 4600) {
3661 
3662  Error("Convert","Unsupported value %d",action);
3663 
3664  } else if (action > kOldxylandau) {
3665  // xylandau
3666 
3667  newActionCode = kxylandau;
3668  newActionParam = action - (kOldxylandau+1);
3669 
3670  } else if (action > kOldlandau) {
3671  // landau, xlandau, ylandau or zlandau
3672 
3673  newActionCode = klandau;
3674  int var = action/100-40;
3675  if (var) newActionCode += var;
3676  newActionParam = action - var*100 - (kOldlandau+1);
3677 
3678  } else if (action > 2500 && action < 2600) {
3679  // xygaus
3680 
3681  newActionCode = kxygaus;
3682  newActionParam = action-2501;
3683 
3684  } else if (action > 2000 && action < 2500) {
3685  // gaus, xgaus, ygaus or zgaus
3686 
3687  newActionCode = kgaus;
3688  int var = action/100-20;
3689  if (var) newActionCode += var;
3690  newActionParam = action - var*100 - (kOldgaus+1);
3691 
3692  } else if (action > 1500 && action < 1600) {
3693  // xyexpo
3694 
3695  newActionCode = kxyexpo;
3696  newActionParam = action-1501;
3697 
3698  } else if (action > 1000 && action < 1500) {
3699  // expo or xexpo or yexpo or zexpo
3700 
3701  newActionCode = kexpo;
3702  int var = action/100-10;
3703  if (var) newActionCode += var;
3704  newActionParam = action - var*100 - (kOldexpo+1);
3705 
3706  } if (action > 100 && action < 200) {
3707  // Parameter substitution
3708 
3709  newActionCode = kParameter;
3710  newActionParam = action - 101;
3711  }
3712 
3713  SetAction( j, newActionCode, newActionParam );
3714 
3715  }
3716  if (i!=j) {
3717  fNoper -= (i-j);
3718  }
3719 
3720 }
3721 
3722 
3723 /////////////////////////////////////////////////////////////////////////////////
3724 
3725 
3726 ////////////////////////////////////////////////////////////////////////////////
3727 /// TOper offset - helper class for TFormula*
3728 /// specify type of operand
3729 /// fTypeX = kVariable
3730 /// = kParameter
3731 /// = kConstant
3732 /// fOffestX = offset in corresponding array
3733 
3734 TOperOffset::TOperOffset()
3735 {
3736  fType0=0;
3737  fType1=0;
3738  fType2=0;
3739  fType3=0;
3740  fOffset0=0;
3741  fOffset1=0;
3742  fOffset2=0;
3743  fOffset3=0;
3744  fOldAction=0;
3745  fToJump=0;
3746 }
3747 
3748 
3749 ////////////////////////////////////////////////////////////////////////////////
3750 /// MakePrimitive
3751 /// find TFormulaPrimitive replacement for some operands
3752 
3753 void TFormula::MakePrimitive(const char *expr, Int_t pos)
3754 {
3755  TString cbase(expr);
3756  cbase.ReplaceAll("Double_t ","");
3757  int paran = cbase.First("(");
3758  // int nargs = 0;
3759  if (paran>0) {
3760  //nargs = 1;
3761  cbase[paran]=0;
3762  }
3763 
3764  if (cbase=="<") cbase="XlY";
3765  if (cbase=="<=") cbase="XleY";
3766  if (cbase==">") cbase="XgY";
3767  if (cbase==">=") cbase="XgeY";
3768  if (cbase=="==" && GetActionOptimized(pos)!=kStringEqual) cbase="XeY";
3769  if (cbase=="!=" && GetActionOptimized(pos)!=kStringNotEqual) cbase="XneY";
3770 
3771  ROOT::v5::TFormulaPrimitive *prim = ROOT::v5::TFormulaPrimitive::FindFormula(cbase ,paran>0 ? cbase.Data() + paran + 1 : (const char*)0);
3772  if (prim) {
3773  fPredefined[pos] = prim;
3774  if (prim->fType==10) {
3775  SetActionOptimized(pos, kFD1);
3776  }
3777  if (prim->fType==110) {
3778  SetActionOptimized(pos, kFD2);
3779  }
3780  if (prim->fType==1110) {
3781  SetActionOptimized(pos, kFD3);
3782  }
3783  if (prim->fType==-1) {
3784  SetActionOptimized(pos, kFDM);
3785  }
3786  if (prim->fType==0){
3787  SetActionOptimized(pos,kConstant,fNconst);
3788  fConst[fNconst] = prim->Eval(0);
3789  fNconst++;
3790  }
3791  return;
3792  }
3793 }
3794 
3795 
3796 ////////////////////////////////////////////////////////////////////////////////
3797 /// MI include
3798 ///
3799 /// Optimize formula
3800 /// 1.) Minimize the number of operands
3801 /// a.) several operanands are glued togther
3802 /// b.) some primitive functions glued together - exemp. (x+y) => PlusXY(x,y)
3803 /// c.) maximize number of standard calls minimizing number of jumps in Eval cases
3804 /// d.) variables, parameters and constants are mapped - using fOperOfssets0
3805 /// Eval procedure use direct acces to data (only one corresponding case statement in eval procedure)
3806 ///
3807 /// pdata[operand={Var,Par,Const}][offset]
3808 /// pdata[fOperOffsets0[i]][fOperOffset1[i+1]]
3809 /// 2.) The fastest evaluation function is chosen at the end
3810 /// a.) fOptimal := pointer to the fastest function for given evaluation string
3811 /// switch(GetActionOptimized(0)){
3812 /// case kData : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive0; break;}
3813 /// case kUnary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive1; break;}
3814 /// case kBinary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive2; break;}
3815 /// case kThree : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive3; break;}
3816 /// case kFDM : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive4; break;}
3817 /// }
3818 /// b.) ex. fOptimal = ::EvalPrimitive0 - if it return only variable, constant or parameter
3819 /// = ::EvalParameter1 - if only one unary operation
3820 /// = ::EvalPrimitive2 - if only one binary operation
3821 /// .......
3822 
3823 void TFormula::Optimize()
3824 {
3825  //
3826  // Initialize data members
3827  //
3828 
3829  Int_t i;
3830 
3831  if (fPredefined) { delete [] fPredefined; fPredefined = 0;}
3832  if (fOperOffset) { delete [] fOperOffset; fOperOffset = 0;}
3833  if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = 0;}
3834  if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = 0;}
3835 
3836  fExprOptimized = new TString[fNoper];
3837  fOperOptimized = new Int_t[fNoper];
3838  fPredefined = new ROOT::v5::TFormulaPrimitive*[fNoper];
3839  fOperOffset = new TOperOffset[fNoper];
3840  for (i=0; i<fNoper; i++) {
3841  fExprOptimized[i] = fExpr[i] ;
3842  fOperOptimized[i] = fOper[i];
3843  fPredefined[i]= 0;
3844  }
3845 
3846  //
3847  //Make primitives
3848  //
3849  for (i=0;i<fNoper;i++){
3850  if (fExprOptimized[i].Data()) {
3851  MakePrimitive(fExprOptimized[i].Data(), i);
3852  }
3853  }
3854  //
3855  Int_t maxfound = fNoper+1;
3856  Int_t *offset = new Int_t[maxfound*16];
3857  Int_t *optimized = new Int_t[maxfound];
3858  //
3859  //
3860  ROOT::v5::TFormulaPrimitive* primitive[10];
3861  primitive[0] = ROOT::v5::TFormulaPrimitive::FindFormula("PlusXY");
3862  primitive[1] = ROOT::v5::TFormulaPrimitive::FindFormula("MinusXY");
3863  primitive[2] = ROOT::v5::TFormulaPrimitive::FindFormula("MultXY");
3864  primitive[3] = ROOT::v5::TFormulaPrimitive::FindFormula("DivXY");
3865  primitive[4] = ROOT::v5::TFormulaPrimitive::FindFormula("XpYpZ");
3866  primitive[5] = ROOT::v5::TFormulaPrimitive::FindFormula("XxYxZ");
3867  primitive[6] = ROOT::v5::TFormulaPrimitive::FindFormula("XxYpZ");
3868  primitive[7] = ROOT::v5::TFormulaPrimitive::FindFormula("XpYxZ");
3869  primitive[8] = ROOT::v5::TFormulaPrimitive::FindFormula("Pow2");
3870  primitive[9] = ROOT::v5::TFormulaPrimitive::FindFormula("Pow3");
3871  //
3872  // set data pointers
3873  //
3874  for (i=0;i<fNoper;i++) optimized[i]=0;
3875  //
3876  for (i=0;i<fNoper;i++){
3877  Int_t actionparam = GetActionParamOptimized(i);
3878  Int_t action = GetActionOptimized(i);
3879 
3880  if (action==kBoolOptimize){
3881  //
3882  // optimize booleans
3883  //
3884  fOperOffset[i].fType1 = actionparam/10; // operands to skip
3885  fOperOffset[i].fOffset0 = actionparam%10; // 1 is && , 2 is || - operand
3886  fOperOffset[i].fToJump = i+fOperOffset[i].fType1; // where we should jump
3887  continue;
3888  }
3889  if (action==kJump || action==kJumpIf) {
3890  // Ternary condtional operator
3891  fOperOffset[i].fType1 = action;
3892  fOperOffset[i].fToJump = actionparam;
3893  }
3894  //
3895  if (action==kConstant&&i<fNoper-2){
3896  //
3897  // get offsets for kFDM operands
3898  //
3899  if (GetActionOptimized(i+1)==kConstant && GetActionOptimized(i+2)==kFDM){
3900  optimized[i]=1;
3901  optimized[i+1]=1;
3902  i+=2;
3903  fOperOffset[i].fType0=actionparam;
3904  fOperOffset[i].fOffset0=GetActionParamOptimized(i-1);
3905  Int_t offset2 = int(fConst[fOperOffset[i].fOffset0]+0.4);
3906  fOperOffset[i].fOffset0=offset2;
3907  Int_t nparmax = offset2+fPredefined[i]->fNParameters;
3908  if (nparmax>fNpar){ // increase expected number of parameters
3909  fNpar=nparmax;
3910  }
3911  continue;
3912  }
3913  }
3914  switch(action){
3915  case kVariable : {action=kData; fOperOffset[i].fType0=0; break;}
3916  case kParameter: {action=kData; fOperOffset[i].fType0=1; break;}
3917  case kConstant : {action=kData; fOperOffset[i].fType0=2; break;}
3918  }
3919  //
3920  fOperOffset[i].fOffset0 = GetActionParamOptimized(i);
3921  SetActionOptimized(i,action, actionparam); //set common data option
3922  }
3923  //
3924  //
3925  fNOperOptimized = fNoper;
3926  //
3927  for (i=0; i<fNoper; ++i)
3928  {
3929  //
3930  if (!(GetActionOptimized(i)== kData)) continue;
3931  offset[0] = fOperOffset[i].fType0; //
3932  offset[1] = fOperOptimized[i] & kTFOperMask; // offset
3933 
3934  if ((i+1) >= fNoper) continue;
3935 
3936  if (GetActionOptimized(i+1)==kFD1){
3937  optimized[i] = 1; // to be optimized
3938  i++;
3939  fOperOffset[i].fType0 = offset[0];
3940  fOperOffset[i].fOffset0 = offset[1];
3941  SetActionOptimized(i ,kUnary);
3942  continue;
3943  }
3944  if (GetActionOptimized(i+1)==kAdd){
3945  optimized[i] = 1; // to be optimized
3946  i++;
3947  fOperOffset[i].fType0 = offset[0];
3948  fOperOffset[i].fOffset0 = offset[1];
3949  SetActionOptimized(i ,kPlusD);
3950  continue;
3951  }
3952  if (GetActionOptimized(i+1)==kMultiply){
3953  optimized[i] = 1; // to be optimized
3954  i++;
3955  fOperOffset[i].fType0 = offset[0];
3956  fOperOffset[i].fOffset0 = offset[1];
3957  SetActionOptimized(i,kMultD);
3958  continue;
3959  }
3960 
3961  if ((i+2) >= fNoper) continue;
3962 
3963  //
3964  //Binary operators
3965  if (!(GetActionOptimized(i+1)== kData)) continue;
3966  offset[2] = fOperOffset[i+1].fType0;
3967  offset[3] = fOperOptimized[i+1] & kTFOperMask; // offset
3968  //
3969  if (GetActionOptimized(i+2)==kFD2 || GetActionOptimized(i+2)==kAdd ||GetActionOptimized(i+2)==kSubstract||
3970  GetActionOptimized(i+2)==kMultiply || GetActionOptimized(i+2)==kDivide){
3971 
3972  optimized[i] = 1; // to be optimized
3973  optimized[i+1] = 1; // to be optimized
3974  i+=2;
3975  //
3976  fOperOffset[i].fType0 = offset[0];
3977  fOperOffset[i].fOffset0 = offset[1];
3978  fOperOffset[i].fType1 = offset[2];
3979  fOperOffset[i].fOffset1 = offset[3];
3980  fOperOffset[i].fType2 = GetActionOptimized(i); //remember old action
3981  if (GetActionOptimized(i)==kAdd) {fPredefined[i] = primitive[0];}
3982  if (GetActionOptimized(i)==kSubstract) {fPredefined[i] = primitive[1];}
3983  if (GetActionOptimized(i)==kMultiply) {
3984  fPredefined[i]=primitive[2];
3985  if (offset[0]==offset[2]&&offset[1]==offset[3]) {
3986  fPredefined[i] = primitive[8];
3987  SetActionOptimized(i,kUnary);
3988  continue;
3989  }
3990  }
3991  if (GetActionOptimized(i)==kDivide) {
3992  fPredefined[i] = primitive[3];
3993  }
3994  SetActionOptimized(i,kBinary);
3995  continue;
3996  }
3997 
3998  if ((i+3) >= fNoper) continue;
3999 
4000  //
4001  //operator 3
4002  //
4003  if (!(GetActionOptimized(i+2)== kData)) continue;
4004  offset[4] = fOperOffset[i+2].fType0;
4005  offset[5] = fOperOptimized[i+2] & kTFOperMask; // offset
4006  //
4007  if (GetActionOptimized(i+3)==kFD3|| ( (GetActionOptimized(i+3)==kAdd||GetActionOptimized(i+3)==kMultiply) &&
4008  (GetActionOptimized(i+4)==kAdd||GetActionOptimized(i+4)==kMultiply) ) ){
4009  optimized[i+0] = 1; // to be optimized
4010  optimized[i+1] = 1; // to be optimized
4011  optimized[i+2] = 1; // to be optimized
4012  i+=3;
4013  //
4014  fOperOffset[i].fType0 = offset[0];
4015  fOperOffset[i].fOffset0 = offset[1];
4016  fOperOffset[i].fType1 = offset[2];
4017  fOperOffset[i].fOffset1 = offset[3];
4018  fOperOffset[i].fType2 = offset[4];
4019  fOperOffset[i].fOffset2 = offset[5];
4020  //
4021  fOperOffset[i].fOldAction = GetActionOptimized(i); //remember old action
4022  if (GetActionOptimized(i)==kFD3) {
4023  SetActionOptimized(i,kThree);
4024  continue;
4025  }
4026  Int_t action=0;
4027  Int_t action2=kThree;
4028  if (GetActionOptimized(i)==kAdd&&GetActionOptimized(i+1)==kAdd) action=4;
4029  if (GetActionOptimized(i)==kMultiply&&GetActionOptimized(i+1)==kMultiply) {
4030  action=5;
4031  if (offset[0]==offset[2]&&offset[1]==offset[3]&&offset[0]==offset[4]&&offset[1]==offset[5]){
4032  fPredefined[i]=primitive[9];
4033  action2=kUnary;
4034  action =9;
4035  }
4036  }
4037  if (GetActionOptimized(i)==kAdd&&GetActionOptimized(i+1)==kMultiply) action=6;
4038  if (GetActionOptimized(i)==kMultiply&&GetActionOptimized(i+1)==kAdd) action=7;
4039  //
4040  optimized[i]=1;
4041  i++;
4042  fOperOffset[i].fType0 = offset[0];
4043  fOperOffset[i].fOffset0 = offset[1];
4044  fOperOffset[i].fType1 = offset[2];
4045  fOperOffset[i].fOffset1 = offset[3];
4046  fOperOffset[i].fType2 = offset[4];
4047  fOperOffset[i].fOffset2 = offset[5];
4048  fPredefined[i]=primitive[action];
4049  SetActionOptimized(i,action2);
4050  continue;
4051  }
4052  }
4053  //
4054  //
4055  Int_t operO=0;
4056  TString expr="";
4057  Int_t *map0 = new Int_t[maxfound]; //remapping of the operands
4058  Int_t *map1 = new Int_t[maxfound]; //remapping of the operands
4059  for (i=0;i<fNoper;i++){
4060  map0[i] = operO;
4061  map1[operO] = i;
4062  fOperOptimized[operO] = fOperOptimized[i];
4063  fPredefined[operO] = fPredefined[i];
4064  fOperOffset[operO] = fOperOffset[i];
4065  expr += fExprOptimized[i];
4066  if (optimized[i]==0){
4067  fExprOptimized[operO] = expr;
4068  expr = "";
4069  operO++;
4070  }else{
4071  expr += ",";
4072  }
4073  }
4074  //
4075  // Recalculate long jump for Boolen optimize
4076  //
4077  for (i=0; i<fNOperOptimized; i++){
4078  Int_t optaction = GetActionOptimized(i);
4079  if (optaction==kBoolOptimize){
4080  Int_t oldpos = fOperOffset[i].fToJump;
4081  Int_t newpos = oldpos==fNoper ? fNOperOptimized : map0[oldpos];
4082  fOperOffset[i].fToJump = newpos; // new position to jump
4083  Int_t actionop = GetActionParamOptimized(i) % 10;
4084  switch (actionop) {
4085  case 1: SetActionOptimized(i,kBoolOptimizeAnd,newpos); break;
4086  case 2: SetActionOptimized(i,kBoolOptimizeOr,newpos); break;
4087  }
4088  } else if (optaction==kJump || optaction==kJumpIf) {
4089  Int_t oldpos = fOperOffset[i].fToJump;
4090  Int_t newpos = oldpos==fNoper ? fNOperOptimized : map0[oldpos];
4091  fOperOffset[i].fToJump = newpos; // new position to jump
4092  SetActionOptimized(i,optaction,newpos);
4093  }
4094  }
4095 
4096 
4097  fNOperOptimized = operO;
4098  //
4099  fOptimal= (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalParFast;
4100  if (fNOperOptimized==1) {
4101  switch(GetActionOptimized(0)){
4102  case kData : {fOptimal= (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive0; break;}
4103  case kUnary : {fOptimal= (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive1; break;}
4104  case kBinary : {fOptimal= (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive2; break;}
4105  case kThree : {fOptimal= (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive3; break;}
4106  case kFDM : {fOptimal= (ROOT::v5::TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive4; break;}
4107  }
4108  }
4109 
4110  delete [] map1;
4111  delete [] map0;
4112  delete [] offset;
4113  delete [] optimized;
4114 }
4115 
4116 
4117 ////////////////////////////////////////////////////////////////////////////////
4118 /// Evaluate primitive formula
4119 
4120 Double_t TFormula::EvalPrimitive(const Double_t *x, const Double_t *params)
4121 {
4122  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4123  Double_t result = pdata[fOperOffset->fType0][fOperOffset->fOffset0];
4124  switch((fOperOptimized[0] >> kTFOperShift)) {
4125  case kData : return result;
4126  case kUnary : return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
4127  case kBinary :return (fPredefined[0]->fFunc110)(result,
4128  pdata[fOperOffset->fType1][fOperOffset->fOffset1]);
4129 
4130  case kThree :return (fPredefined[0]->fFunc1110)(result, pdata[fOperOffset->fType1][fOperOffset->fOffset1],
4131  pdata[fOperOffset->fType2][fOperOffset->fOffset2]);
4132  case kFDM : return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
4133  (Double_t*)&params[fOperOffset->fOffset0]);
4134  }
4135  return 0;
4136 }
4137 
4138 
4139 ////////////////////////////////////////////////////////////////////////////////
4140 /// Evaluate primitive formula
4141 
4142 Double_t TFormula::EvalPrimitive0(const Double_t *x, const Double_t *params)
4143 {
4144  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4145  return pdata[fOperOffset->fType0][fOperOffset->fOffset0];
4146 }
4147 
4148 
4149 ////////////////////////////////////////////////////////////////////////////////
4150 /// Evaluate primitive formula
4151 
4152 Double_t TFormula::EvalPrimitive1(const Double_t *x, const Double_t *params)
4153 {
4154  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4155  return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
4156 }
4157 
4158 
4159 ////////////////////////////////////////////////////////////////////////////////
4160 /// Evaluate primitive formula
4161 
4162 Double_t TFormula::EvalPrimitive2(const Double_t *x, const Double_t *params)
4163 {
4164  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4165  return (fPredefined[0]->fFunc110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0],
4166  pdata[fOperOffset->fType1][fOperOffset->fOffset1]);
4167 }
4168 
4169 
4170 ////////////////////////////////////////////////////////////////////////////////
4171 /// Evaluate primitive formula
4172 
4173 Double_t TFormula::EvalPrimitive3(const Double_t *x, const Double_t *params)
4174 {
4175  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4176  return (fPredefined[0]->fFunc1110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0], pdata[fOperOffset->fType1][fOperOffset->fOffset1],
4177  pdata[fOperOffset->fType2][fOperOffset->fOffset2]);
4178 }
4179 
4180 
4181 ////////////////////////////////////////////////////////////////////////////////
4182 /// Evaluate primitive formula
4183 
4184 Double_t TFormula::EvalPrimitive4(const Double_t *x, const Double_t *params)
4185 {
4186  const Double_t *par = (params!=0)?params:fParams;
4187  return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
4188  (Double_t*)&par[fOperOffset->fOffset0]);
4189 }
4190 
4191 
4192 ////////////////////////////////////////////////////////////////////////////////
4193 /// Evaluate this formula.
4194 ///
4195 /// The current value of variables x,y,z,t is passed through the pointer x.
4196 /// The parameters used will be the ones in the array params if params is given
4197 /// otherwise parameters will be taken from the stored data members fParams
4198 ///Begin_Html
4199 
4200 Double_t TFormula::EvalParFast(const Double_t *x, const Double_t *uparams)
4201 {
4202  /*
4203  <img src="gif/eval.gif">
4204  */
4205  //End_Html
4206 
4207  const Double_t *pdata[3] = {x,(uparams!=0)?uparams:fParams, fConst};
4208  //
4209  Int_t i,j;
4210  Double_t tab[kMAXFOUND];
4211  const char *stringStack[gMAXSTRINGFOUND];
4212  Double_t param_calc[kMAXFOUND];
4213  char *string_calc[gMAXSTRINGFOUND];
4214  Int_t precalculated = 0;
4215  Int_t precalculated_str = 0;
4216 
4217  Double_t *params;
4218 
4219  if (uparams) {
4220  //for (j=0;j<fNpar;j++) fParams[j] = params[j];
4221  params = const_cast<Double_t*>(uparams);
4222  } else {
4223  params = fParams;
4224  }
4225 
4226  //if (params) {
4227  // for (j=0;j<fNpar;j++) fParams[j] = params[j];
4228  //}
4229  UInt_t pos = 0;
4230  UInt_t strpos = 0;
4231  // for (i=0; i<fNoper; ++i) {
4232  for (i=0; i<fNOperOptimized; ++i) {
4233  //
4234  const int oper = fOperOptimized[i];
4235  const int opcode = oper >> kTFOperShift;
4236 
4237  switch(opcode) { // FREQUENTLY USED OPERATION
4238  case kData : tab[pos] = pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; pos++;continue;
4239  case kPlusD : tab[pos-1]+= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
4240  case kMultD : tab[pos-1]*= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
4241  case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
4242  case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
4243  case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
4244  case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
4245  else tab[pos-1] /= tab[pos];
4246  continue;
4247  case kUnary : tab[pos] = (fPredefined[i]->fFunc10)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]); pos++;continue;
4248  case kBinary : tab[pos] = (fPredefined[i]->fFunc110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
4249  pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1]);pos++;continue;
4250 
4251  case kThree : tab[pos] = (fPredefined[i]->fFunc1110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
4252  pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1],
4253  pdata[fOperOffset[i].fType2][fOperOffset[i].fOffset2]); pos++; continue;
4254 
4255  case kFDM : tab[pos] = (fPredefined[i]->fFuncG)(&x[fOperOffset[i].fType0],&params[fOperOffset[i].fOffset0]); pos++;continue;
4256  case kFD1 : tab[pos-1] =(fPredefined[i]->fFunc10)(tab[pos-1]); continue;
4257  case kFD2 : pos--; tab[pos-1] = (fPredefined[i]->fFunc110)(tab[pos-1],tab[pos]); continue;
4258  case kFD3 : pos-=2; tab[pos-1] = (fPredefined[i]->fFunc1110)(tab[pos-1],tab[pos],tab[pos+1]); continue;
4259  }
4260  //
4261  switch(opcode) {
4262  case kBoolOptimizeAnd: {
4263  if (!tab[pos-1]) i=fOperOffset[i].fToJump;
4264  continue;
4265  }
4266  case kBoolOptimizeOr: {
4267  if (tab[pos-1]) i=fOperOffset[i].fToJump;
4268  continue;
4269  }
4270  case kAnd : pos--; tab[pos-1] = (bool)tab[pos]; continue; // use the fact that other were check before - see bool optimize
4271  case kOr : pos--; tab[pos-1] = (bool)tab[pos]; continue;
4272  }
4273  switch(opcode) {
4274  // case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
4275  case kabs : if (tab[pos-1]<0) tab[pos-1]=-tab[pos-1]; continue;
4276  case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
4277  case kint : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
4278  case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
4279 
4280  case kModulo : {pos--;
4281  Long64_t int1((Long64_t)tab[pos-1]);
4282  Long64_t int2((Long64_t)tab[pos]);
4283  tab[pos-1] = Double_t(int1%int2);
4284  continue;}
4285 
4286 
4287  case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExprOptimized[i].Data(); pos++; tab[pos-1] = 0; continue; }
4288  case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
4289 
4290  case kstrstr : strpos -= 2; pos-=2; pos++;
4291  if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
4292  else tab[pos-1]=0;
4293  continue;
4294  case kpi : pos++; tab[pos-1] = TMath::ACos(-1); continue;
4295 
4296 
4297  case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
4298 
4299  case krndm : pos++; tab[pos-1] = gRandom->Rndm(1); continue;
4300 
4301 
4302  case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
4303  else tab[pos-1]=0;
4304  continue;
4305  case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
4306  else tab[pos-1]=0;
4307  continue;
4308  case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1;
4309  continue;
4310 
4311  case kStringEqual : strpos -= 2; pos -=2 ; pos++;
4312  if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
4313  else tab[pos-1]=0;
4314  continue;
4315  case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
4316  if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
4317  else tab[pos-1]=0;
4318  continue;
4319 
4320  case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
4321  case kBitOr : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
4322  case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
4323  case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
4324 
4325  case kJump : i = (oper & kTFOperMask); continue;
4326  case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
4327 
4328  case kBoolOptimize: {
4329  // boolean operation optimizer
4330 
4331  int param = (oper & kTFOperMask);
4332  int op = param % 10; // 1 is && , 2 is ||
4333 
4334  if (op == 1 && (!tab[pos-1]) ) {
4335  // &&: skip the right part if the left part is already false
4336 
4337  i += param / 10;
4338 
4339  // Preserve the existing behavior (i.e. the result of a&&b is
4340  // either 0 or 1)
4341  tab[pos-1] = 0;
4342 
4343  } else if (op == 2 && tab[pos-1] ) {
4344  // ||: skip the right part if the left part is already true
4345 
4346  i += param / 10;
4347 
4348  // Preserve the existing behavior (i.e. the result of a||b is
4349  // either 0 or 1)
4350  tab[pos-1] = 1;
4351 
4352  }
4353 
4354  continue;
4355  }
4356 
4357  }
4358  switch(opcode) {
4359 
4360 #define R__EXPO(var) \
4361  { \
4362  pos++; int param = (oper & kTFOperMask); \
4363  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]); \
4364  continue; \
4365  }
4366  // case kexpo:
4367  case kxexpo: R__EXPO(0);
4368  case kyexpo: R__EXPO(1);
4369  case kzexpo: R__EXPO(2);
4370  case kxyexpo:{ pos++; int param = (oper & kTFOperMask);
4371  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
4372  continue; }
4373 #ifdef R__GAUS
4374 #undef R__GAUS
4375 #endif
4376 #define R__GAUS(var) \
4377  { \
4378  pos++; int param = (oper & kTFOperMask); \
4379  tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1], \
4380  params[param+2],IsNormalized()); \
4381  continue; \
4382  }
4383 
4384  // case kgaus:
4385  case kxgaus: R__GAUS(0);
4386  case kygaus: R__GAUS(1);
4387  case kzgaus: R__GAUS(2);
4388  case kxygaus: { pos++; int param = (oper & kTFOperMask);
4389  Double_t intermede1;
4390  if (params[param+2] == 0) {
4391  intermede1=1e10;
4392  } else {
4393  intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
4394  }
4395  Double_t intermede2;
4396  if (params[param+4] == 0) {
4397  intermede2=1e10;
4398  } else {
4399  intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
4400  }
4401  tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
4402  continue; }
4403 
4404 #define R__LANDAU(var) \
4405  { \
4406  pos++; const int param = (oper & kTFOperMask); \
4407  tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
4408  continue; \
4409  }
4410  // case klandau:
4411  case kxlandau: R__LANDAU(0);
4412  case kylandau: R__LANDAU(1);
4413  case kzlandau: R__LANDAU(2);
4414  case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
4415  Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
4416  Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
4417  tab[pos-1] = params[param]*intermede1*intermede2;
4418  continue;
4419  }
4420 
4421 #define R__POLY(var) \
4422  { \
4423  pos++; int param = (oper & kTFOperMask); \
4424  tab[pos-1] = 0; Double_t intermede = 1; \
4425  Int_t inter = param/100; /* arrondit */ \
4426  Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
4427  for (j=0 ;j<inter+1;j++) { \
4428  tab[pos-1] += intermede*params[j+int1]; \
4429  intermede *= x[var]; \
4430  } \
4431  continue; \
4432  }
4433  // case kpol:
4434  case kxpol: R__POLY(0);
4435  case kypol: R__POLY(1);
4436  case kzpol: R__POLY(2);
4437 
4438  case kDefinedVariable : {
4439  if (!precalculated) {
4440  precalculated = 1;
4441  for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
4442  }
4443  pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
4444  continue;
4445  }
4446 
4447  case kDefinedString : {
4448  int param = (oper & kTFOperMask);
4449  if (!precalculated_str) {
4450  precalculated_str=1;
4451  for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
4452  }
4453  strpos++; stringStack[strpos-1] = string_calc[param];
4454  pos++; tab[pos-1] = 0;
4455  continue;
4456  }
4457 
4458  case kFunctionCall: {
4459  // an external function call
4460 
4461  int param = (oper & kTFOperMask);
4462  int fno = param / 1000;
4463  int nargs = param % 1000;
4464 
4465  // Retrieve the function
4466  TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
4467 
4468  // Set the arguments
4469  method->ResetParam();
4470  if (nargs) {
4471  UInt_t argloc = pos-nargs;
4472  for(j=0;j<nargs;j++,argloc++,pos--) {
4473  method->SetParam(tab[argloc]);
4474  }
4475  }
4476  pos++;
4477  Double_t ret;
4478  method->Execute(ret);
4479  tab[pos-1] = ret; // check for the correct conversion!
4480 
4481  continue;
4482  };
4483  }
4484  if (!TestBit(kOptimizationError)) {
4485  SetBit(kOptimizationError);
4486  Warning("EvalParFast","Found an unsupported optmized opcode (%d)",oper >> kTFOperShift);
4487  }
4488  }
4489  Double_t result0 = tab[0];
4490  return result0;
4491 
4492 }
4493 
4494 
4495 ////////////////////////////////////////////////////////////////////////////////
4496 /// Pre compile function
4497 
4498 Int_t TFormula::PreCompile()
4499 {
4500  TString str = fTitle;
4501  if (str.Length()<3) return 1;
4502  if (str[str.Length()-1]!='+'&&str[str.Length()-2]!='+') return 1;
4503  str[str.Length()-2]=0;
4504  TString funName("preformula_");
4505  funName += fName;
4506  if (ROOT::v5::TFormulaPrimitive::FindFormula(funName)) return 0;
4507  TString fileName;
4508  fileName.Form("/tmp/%s.C",funName.Data());
4509 
4510  FILE *hf;
4511  hf = fopen(fileName.Data(),"w");
4512  if (hf == 0) {
4513  Error("PreCompile","Unable to open the file %s for writing.",fileName.Data());
4514  return 1;
4515  }
4516  fprintf(hf, "/////////////////////////////////////////////////////////////////////////\n");
4517  fprintf(hf, "// This code has been automatically generated \n");
4518  //
4519  fprintf(hf, "Double_t %s(Double_t *x, Double_t *p){",funName.Data());
4520  fprintf(hf, "return (%s);\n}",str.Data());
4521 
4522  // fprintf("ROOT::v5::TFormulaPrimitive::AddFormula(new ROOT::v5::TFormulaPrimitive(\"%s::%s\",\"%s::%s\",(ROOT::v5::TFormulaPrimitive::GenFunc0)%s::%s));\n",
4523  // clname,method->GetName(),clname,method->GetName(),clname,method->GetName());
4524  fclose(hf);
4525 
4526  return 0;
4527 
4528 
4529 }
4530 
4531 
4532 ////////////////////////////////////////////////////////////////////////////////
4533 /// static function to set the maximum value of 3 parameters
4534 /// -maxop : maximum number of operations
4535 /// -maxpar : maximum number of parameters
4536 /// -maxconst : maximum number of constants
4537 /// None of these parameters cannot be less than 10 (default is 1000)
4538 /// call this function to increase one or all maxima when processing
4539 /// very complex formula, eg TFormula::SetMaxima(100000,1000,1000000);
4540 /// If you process many functions with a small number of operations/parameters
4541 /// you may gain some memory and performance by decreasing these values.
4542 
4543 void TFormula::SetMaxima(Int_t maxop, Int_t maxpar, Int_t maxconst)
4544 {
4545  gMAXOP = TMath::Max(10,maxop);
4546  gMAXPAR = TMath::Max(10,maxpar);
4547  gMAXCONST = TMath::Max(10,maxconst);
4548 }
4549 
4550 ////////////////////////////////////////////////////////////////////////////////
4551 /// static function to get the maximum value of 3 parameters
4552 /// -maxop : maximum number of operations
4553 /// -maxpar : maximum number of parameters
4554 /// -maxconst : maximum number of constants
4555 
4556 void TFormula::GetMaxima(Int_t& maxop, Int_t& maxpar, Int_t& maxconst)
4557 {
4558  maxop = gMAXOP;
4559  maxpar = gMAXPAR;
4560  maxconst = gMAXCONST;
4561 }
4562 
4563  } // end namespace v5
4564 
4565 } // end namespace ROOT
virtual void Clear(Option_t *option="")
Set name and title to empty strings ("").
Definition: TFormula.cxx:591
Double_t ACosH(Double_t)
Definition: TMath.cxx:80
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:52
double par[1]
Definition: unuranDistr.cxx:38
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:864
#define R__EXPO(var)
Double_t Landau(Double_t x, Double_t mpv=0, Double_t sigma=1, Bool_t norm=kFALSE)
The LANDAU function.
Definition: TMath.cxx:473
RooCmdArg Optimize(Int_t flag=2)
An array of TObjects.
Definition: TObjArray.h:39
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
Double_t TanH(Double_t)
Definition: TMath.h:436
long long Long64_t
Definition: RtypesCore.h:69
static double p3(double t, double a, double b, double c, double d)
Double_t Eval(Double_t x) const
Definition: TFormula.cxx:2538
Bool_t IsReading() const
Definition: TBuffer.h:81
Double_t Log(Double_t x)
Definition: TMath.h:526
short Version_t
Definition: RtypesCore.h:61
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
Ssiz_t Length() const
Definition: TString.h:390
Collectable string class.
Definition: TObjString.h:32
float Float_t
Definition: RtypesCore.h:53
virtual Double_t Rndm(Int_t i=0)
Machine independent random number generator.
Definition: TRandom.cxx:512
static const EReturnType kOther
Definition: TMethodCall.h:50
const char Option_t
Definition: RtypesCore.h:62
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:328
double T(double x)
Definition: ChebyshevPol.h:34
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:635
void SetParameters(const Double_t *params)
Definition: TFormula.cxx:2401
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
#define BIT(n)
Definition: Rtypes.h:120
static Int_t gMAXCONST
Definition: TFormula_v5.cxx:32
void SetParNames(const char *name0="p0", const char *name1="p1", const char *name2="p2", const char *name3="p3", const char *name4="p4", const char *name5="p5", const char *name6="p6", const char *name7="p7", const char *name8="p8", const char *name9="p9", const char *name10="p10")
Definition: TFormula.cxx:2438
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
#define R__ASSERT(e)
Definition: TError.h:98
#define R__LANDAU(var)
virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss)=0
#define gROOT
Definition: TROOT.h:340
Basic string class.
Definition: TString.h:137
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:170
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1088
int Int_t
Definition: RtypesCore.h:41
virtual void Copy(TObject &f1) const
Copy this to obj.
Definition: TFormula.cxx:518
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:63
const Bool_t kFALSE
Definition: Rtypes.h:92
#define gInterpreter
Definition: TInterpreter.h:502
const Int_t kTFOperMask
Definition: TFormula.h:38
Int_t GetParNumber(const char *name) const
Definition: TFormula.cxx:2251
const TObject * GetLinearPart(Int_t i) const
Definition: TFormula.cxx:1968
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:592
const Int_t gMAXSTRINGFOUND
Definition: TFormula_v5.cxx:33
Short_t Abs(Short_t d)
Definition: TMathBase.h:110
#define R__GAUS(var)
void Print(Option_t *option="") const
print the formula and its attributes
Definition: TFormula.cxx:2682
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Definition: TMath.h:501
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:732
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:625
const char * Data() const
Definition: TString.h:349
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TObject.cxx:203
virtual ~TFormula()
Definition: TFormula.cxx:274
Double_t x[n]
Definition: legend1.C:17
void Class()
Definition: Class.C:29
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
UChar_t mod R__LOCKGUARD2(gSrvAuthenticateMutex)
virtual void Copy(TObject &named) const
Copy this to obj.
Definition: TNamed.cxx:83
void SetParameter(const char *name, Double_t value)
Definition: TFormula.cxx:2321
Double_t ASinH(Double_t)
Definition: TMath.cxx:67
Double_t Log10(Double_t x)
Definition: TMath.h:529
static double p2(double t, double a, double b, double c)
TFormula & operator=(const TFormula &rhs)
Definition: TFormula.cxx:430
TString & Append(const char *cs)
Definition: TString.h:492
std::vector< std::vector< double > > Data
TString GetExpFormula(Option_t *option="") const
return the expression formula If option = "P" replace the parameter names with their values If option...
Definition: TFormula.cxx:2610
Double_t ATan2(Double_t, Double_t)
Definition: TMath.h:454
const Int_t kMAXFOUND
Definition: TFormula.h:37
Method or function calling interface.
Definition: TMethodCall.h:41
void SetParName(Int_t ipar, const char *name)
Definition: TFormula.cxx:2454
void Error(const char *location, const char *msgfmt,...)
Double_t Eval(Double_t *x)
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:91
#define R__POLY(var)
Int_t GetNpar() const
Definition: TFormula.h:175
ClassInfo_t * GetClassInfo() const
Definition: TClass.h:391
The F O R M U L A class.
Definition: TFormula.h:89
TClass * IsA() const
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2321
unsigned int UInt_t
Definition: RtypesCore.h:42
char * Form(const char *fmt,...)
static Int_t gMAXOP
Definition: TFormula_v5.cxx:32
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
Double_t ACos(Double_t)
Definition: TMath.h:445
static double p1(double t, double a, double b)
const UChar_t kTFOperShift
Definition: TFormula.h:39
ClassImp(ROOT::v5::TFormula) namespace ROOT
Definition: TFormula_v5.cxx:36
void Warning(const char *location, const char *msgfmt,...)
R__EXTERN TRandom * gRandom
Definition: TRandom.h:62
TString & String()
Definition: TObjString.h:52
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2240
#define Printf
Definition: TGeoToOCC.h:18
Double_t Cos(Double_t)
Definition: TMath.h:424
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
long Long_t
Definition: RtypesCore.h:50
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=0)=0
int Ssiz_t
Definition: RtypesCore.h:63
TFunction * GetMethod()
Returns the TMethod describing the method to be executed.
Double_t Exp(Double_t x)
Definition: TMath.h:495
virtual const char * GetPrototype() const
Returns the prototype of a function as defined by CINT, or 0 in case of error.
Definition: TFunction.cxx:245
double f(double x)
void ResetParam()
Reset parameter list. To be used before the first call the SetParam().
double Double_t
Definition: RtypesCore.h:55
unsigned long ULong_t
Definition: RtypesCore.h:51
Double_t y[n]
Definition: legend1.C:17
static TFormulaPrimitive * FindFormula(const char *name)
Int_t Compile(const char *expression="")
Definition: TFormula.cxx:479
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2881
TCanvas * slash()
Definition: slash.C:1
#define name(a, b)
Definition: linkTestLib0.cpp:5
const char * GetParName(Int_t ipar) const
Definition: TFormula.cxx:2288
Mother of all ROOT objects.
Definition: TObject.h:58
void Execute(const char *, const char *, int *=0)
Execute method on this object with the given parameter string, e.g.
Definition: TMethodCall.h:68
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
Double_t Sin(Double_t)
Definition: TMath.h:421
void SetParam(Long_t l)
Add a long method parameter.
static Int_t gMAXPAR
Definition: TFormula_v5.cxx:32
Double_t ASin(Double_t)
Definition: TMath.h:439
Double_t(TObject::* TFuncG)(const Double_t *, const Double_t *) const
Double_t SinH(Double_t)
Definition: TMath.h:430
double result[121]
Double_t Sqrt(Double_t x)
Definition: TMath.h:464
const UInt_t kOptimizationError
Definition: TFormula_v5.cxx:34
const Bool_t kTRUE
Definition: Rtypes.h:91
TObject * obj
float value
Definition: math.cpp:443
static char * skip(char **buf, const char *delimiters)
Definition: civetweb.c:1014
const Int_t n
Definition: legend1.C:16
Double_t ATanH(Double_t)
Definition: TMath.cxx:93
Double_t CosH(Double_t)
Definition: TMath.h:433
Double_t GetParameter(const char *name) const
Definition: TFormula.cxx:2263
Double_t Tan(Double_t)
Definition: TMath.h:427
Bool_t IsValid() const
Return true if the method call has been properly initialized and is usable.
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:466
Definition: drr.cxx:518
EReturnType ReturnType()
Returns the return type of the method.
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
virtual Int_t ReadArray(Bool_t *&b)=0
Double_t ATan(Double_t)
Definition: TMath.h:451