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