Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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;
209
210 if (j) {
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")) {
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
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
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(':');
362 if (scopeEnd>0 && functionName[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);
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();
438
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);
458 while ( (objstr=(TObjString*)next()) ) {
459 Analyze(objstr->String(),err,offset);
460 }
461
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 //
476 Int_t args_paran = cbase.First("(");
477 if (args_paran>0){
478 cbase[args_paran]=0;
479 }
480
482 if (prim && (!IsA()->GetBaseClass("TTreeFormula"))) {
483 // TO BE DONE ALSO IN TTREFORMULA - temporary fix MI
484 // Analyze the arguments
485 TIter next(&argArr);
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
717 valeur=find=n=i=j=k=lchain=nomb=virgule=inter=nest = 0;
725
727 const TFormula *oldformula;
729 char t;
730 TString slash("/"), escapedSlash("\/");
731 Int_t inter2 = 0;
732 SetNumber(0);
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) + ")";
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
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
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";
902 actionParam = 0;
904 Int_t optloc = fNoper++;
905
906 // Expression executed if condition is true.
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
911
912 fExpr[fNoper] = "?: else jump";
914 actionParam = 0;
915 // Set jump target.
917 optloc = fNoper++;
918
919 // Expression executed if condition is false.
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
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";
942 actionParam = 2;
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;
951
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";
967 actionParam = 1;
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] = "&&";
977
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;
992 Analyze(ctemp.Data(),err,offset); if (err) return;
993 fExpr[fNoper] = "|";
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;
1009 Analyze(ctemp.Data(),err,offset); if (err) return;
1010 fExpr[fNoper] = "&";
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;
1026 Analyze(ctemp.Data(),err,offset); if (err) return;
1027 fExpr[fNoper] = "<";
1028 actionCode = kLess;
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;
1043 Analyze(ctemp.Data(),err,offset); if (err) return;
1044 fExpr[fNoper] = ">";
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] = "<=";
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] = ">=";
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] = "==";
1098
1100 if (IsString(optloc) != isstring) {
1101 err = 45;
1102 chaine_error = "==";
1103 } else if (isstring) {
1105 }
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] = "!=";
1123
1125 if (IsString(optloc) != isstring) {
1126 err = 45;
1127 chaine_error = "!=";
1128 } else if (isstring) {
1130 }
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;
1144 Analyze(ctemp.Data(),err,offset); if (err) return;
1145 fExpr[fNoper] = "+";
1146 actionCode = kAdd;
1148 fNoper++;
1149 if (!CheckOperands(leftopr,fNoper-1,err)) return;
1150 }
1151 } else {
1152 if (moins != 0) {
1153 if (moins == 1) {
1155 Analyze(ctemp.Data(),err,offset); if (err) return;
1156 fExpr[fNoper] = "-";
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;
1170 Analyze(ctemp.Data(),err,offset); if (err) return;
1171 fExpr[fNoper] = "-";
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;
1187 Analyze(ctemp.Data(),err,offset); if (err) return;
1188 fExpr[fNoper] = "%";
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;
1203 Analyze(ctemp.Data(),err,offset); if (err) return;
1204 fExpr[fNoper] = ">>";
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;
1219 Analyze(ctemp.Data(),err,offset); if (err) return;
1220 fExpr[fNoper] = ">>";
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;
1237 Analyze(ctemp.Data(),err,offset); if (err) return;
1238 fExpr[fNoper] = "*";
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;
1255 Analyze(ctemp.Data(),err,offset); if (err) return;
1256 fExpr[fNoper] = "/";
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;
1277 Analyze(ctemp.Data(),err,offset); if (err) return;
1278 fExpr[fNoper] = "^";
1279 actionCode = kpow;
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 {
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;
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;
1319 }
1320 }
1321 }
1322 }
1323 else {
1324 if (!strchr("0123456789abcdefABCDEF",t) && (j>1)) {
1325 err = 30;
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;
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; }
1342 actionParam = k;
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;
1383 if (k==-3) {
1384 // Error message already issued
1385 err = 1;
1386 } else if (k==-2) {
1387 err = 31;
1389 } else if ( k >= 0 ) {
1390 fExpr[fNoper] = ctemp;
1392 actionParam = k;
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;
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);
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;
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;
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;
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;
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;
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;
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;
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;
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;
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";
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";
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";
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;
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;
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";
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;
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;
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;
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;
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;
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;
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(" ) {
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;
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
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) {
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);
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;
1644 }
1645 }
1646 if (err==0) {
1647 sscanf(ctemp.Data(),"%d",&inter);
1648 if (inter>=0) {
1649 inter += offset;
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
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(") {
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
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
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) {
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);
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;
1730 }
1731 }
1732 if (err==0) {
1733 sscanf(ctemp.Data(),"%d",&inter);
1734 if (inter >= 0) {
1735 inter += offset;
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
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(") {
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
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
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) {
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);
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;
1815 }
1816 }
1817 if (err==0) {
1818 sscanf(ctemp.Data(),"%d",&inter);
1819 if (inter >= 0) {
1820 inter += offset;
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
1834 }
1835
1836 // Look for a polynomial
1837
1838 } else if (chaine(0,3) == "pol" || chaine(1,3) == "pol") {
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;
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;
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) {
1893 actionCode = kpol+(inter2-1);
1894 actionParam = n*100+inter+2;
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;
1924 Analyze(ctemp.Data(),err,offset); if (err) return;
1925 fExpr[fNoper] = "^";
1926 actionCode = kpow;
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
1954 Analyze(ctemp.Data(),err,offset); if (err) return;
1955 fExpr[fNoper] = "strstr";
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;
1985 Analyze(ctemp.Data(),err,offset); if (err) return;
1986 fExpr[fNoper] = "min";
1987 actionCode = kmin;
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;
2012 Analyze(ctemp.Data(),err,offset); if (err) return;
2013 fExpr[fNoper] = "max";
2014 actionCode = kmax;
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;
2037 Analyze(ctemp.Data(),err,offset); if (err) return;
2038 fExpr[fNoper] = "atan2";
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;
2064 Analyze(ctemp.Data(),err,offset); if (err) return;
2065 fExpr[fNoper] = "fmod";
2066 actionCode = kfmod;
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) {
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);
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;
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 }
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;
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
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)){
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){
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.
2692 const char *stringStack[gMAXSTRINGFOUND] = {nullptr};
2694 char *string_calc[gMAXSTRINGFOUND] = {nullptr};
2695 Int_t precalculated = 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);
2901 if (params[param+2] == 0) {
2902 intermede1=1e10;
2903 } else {
2904 intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
2905 }
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) {
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
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/// @note Floats when option contains "p" are printed with `%g` (6 decimals);
3022/// if you need more precision, use instead the non-v5 version of this class.
3023/// @see https://cplusplus.com/reference/cstdio/printf/
3024
3026{
3027 if (fNoper>0) {
3028 TString* tab=new TString[fNoper];
3030 Int_t spos=0;
3031
3032 ismulti[0]=kFALSE;
3033 Int_t optype;
3034 Int_t j;
3035 Int_t ternaryend = -1;
3036 for(Int_t i=0;i<fNoper;i++){
3037 optype = GetAction(i);
3038
3039 if (ternaryend==i) {
3040 // The ? and : have been added to tab[spos-2]
3041 if(ismulti[spos-1]){
3042 tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
3043 } else {
3044 tab[spos-2]=tab[spos-2]+tab[spos-1];
3045 }
3046 spos--;
3047 // Do not call continue since we need to
3048 // do the rest of the loop.
3049 }
3050
3051 // Boolean optimization breakpoint
3052 if (optype==kBoolOptimize) { // -3) {
3053 continue;
3054 }
3055
3056 //Sign inversion
3057 if (optype==kSignInv) { // -1) {
3058 tab[spos-1]="-("+tab[spos-1]+")";
3059 // i++;
3060 continue;
3061 }
3062
3063 //Simple name (parameter,pol0,landau, etc)
3064 if (kexpo<=optype && optype<=kzpol) { // >=0) {
3065 tab[spos]=fExpr[i];
3067 spos++;
3068 continue;
3069 }
3070
3071 //constants, variables x,y,z,t, pi
3072 if ((optype<=151 && optype>=140 && optype!=145) || (optype == 40)) {
3073 tab[spos]=fExpr[i];
3075 spos++;
3076 continue;
3077 }
3078
3079 //Basic operators (+,-,*,/,==,^,etc)
3080 if(((optype>0 && optype<6) || optype==20 ||
3081 (((optype>59 && optype<69) || (optype >75 && optype<82)) && spos>=2))) {
3082 // if(optype==-20 && spos>=2){
3083 if(ismulti[spos-2]){
3084 tab[spos-2]="("+tab[spos-2]+")";
3085 }
3086 if(ismulti[spos-1]){
3087 tab[spos-2]+=fExpr[i]+("("+tab[spos-1]+")");
3088 }else{
3089 tab[spos-2]+=fExpr[i]+tab[spos-1];
3090 }
3091 ismulti[spos-2]=kTRUE;
3092 spos--;
3093 continue;
3094 }
3095 //Ternary condition
3096 if (optype==kJumpIf) {
3097 if(ismulti[spos-1]){
3098 tab[spos-1]="("+tab[spos-1]+")?";
3099 } else {
3100 tab[spos-1]=tab[spos-1]+"?";
3101 }
3102 continue;
3103 }
3104 if (optype==kJump) {
3105 if(ismulti[spos-1]){
3106 tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+"):";
3107 } else {
3108 tab[spos-2]=tab[spos-2]+tab[spos-1]+":";
3109 }
3110 ternaryend = GetActionParam(i) + 1;
3111 spos--;
3112 continue;
3113 }
3114
3115 //Functions
3116 int offset = 0;
3117 TString funcname = fExpr[i];
3118 if((optype>9 && optype<16) ||
3119 (optype>20 && optype<23) ||
3120 (optype>29 && optype<34) ||
3121 (optype>40 && optype<44) ||
3122 (optype>69 && optype<76) ||
3123 (optype==145)) {
3124 //Functions with the format func(x)
3125 offset = -1;
3126 }
3127
3128 if((optype>15 && optype<20) ||
3129 (optype>22 && optype<26)) {
3130 //Functions with the format func(x,y)
3131 offset = -2;
3132 }
3133 if(optype==145) {
3134 int param = (fOper[i] & kTFOperMask);
3135 //int fno = param / 1000;
3136 int nargs = param % 1000;
3137 offset = -nargs;
3138 // The function name contains return type and parameters types we need
3139 // to trim them.
3140 int depth;
3141 for(j=0, depth=0;j<funcname.Length();++j) {
3142 switch (funcname[j]) {
3143 case '<':
3144 ++depth; break;
3145 case '>':
3146 --depth; break;
3147 case ' ':
3148 if (depth==0) {
3149 funcname.Remove(0,j+1);
3150 j = funcname.Length();
3151 break;
3152 }
3153 }
3154 }
3155 Ssiz_t ind = funcname.First('(');
3156 funcname.Remove(ind);
3157 }
3158 if (offset > 0) {
3159 Error("GetExpFormula","Internal error, number of argument found is %d",-offset);
3160 } else if (offset == 0) {
3161 tab[spos]=funcname+"()";
3163 spos += 1;
3164 continue;
3165 } else if (offset<=0 && (spos+offset>=0)) {
3167 for (j=offset+1; j<0; j++){
3168 tab[spos+offset]+=","+tab[spos+j];
3169 }
3170 tab[spos+offset]+=")";
3172 spos += offset+1;
3173 continue;
3174 }
3175 }
3176 if (ternaryend==fNoper) {
3177 // The ? and : have been added to tab[spos-2]
3178 if(ismulti[spos-1]){
3179 tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
3180 } else {
3181 tab[spos-2]=tab[spos-2]+tab[spos-1];
3182 }
3183 spos--;
3184 }
3185
3186 TString ret = "";
3187 if (spos > 0) ret = tab[spos-1];
3188 delete[] tab;
3189 delete[] ismulti;
3190
3191 //if option "p" is specified, return the real values of parameters instead of [0]
3192 TString opt = option;
3193 opt.ToLower();
3194 if (opt.Contains("p")) {
3195 char pb[14];
3196 char pbv[100];
3197 for (j=0;j<fNpar;j++) {
3198 snprintf(pb,sizeof(pb),"[%d]",j);
3199 snprintf(pbv, 100, "%g", fParams[j]);
3200 ret.ReplaceAll(pb,pbv);
3201 }
3202 ret.ReplaceAll("--","+");
3203 ret.ReplaceAll("+-","-");
3204 }
3205 return ret;
3206 } else{
3207 TString ret="";
3208 return ret;
3209 }
3210}
3211
3212////////////////////////////////////////////////////////////////////////////////
3213/// Return linear part.
3214
3216{
3217 if (!fLinearParts.IsEmpty())
3218 return fLinearParts.UncheckedAt(i);
3219 return nullptr;
3220}
3221
3222////////////////////////////////////////////////////////////////////////////////
3223/// Return value of parameter number ipar.
3224
3226{
3227 if (ipar <0 || ipar >= fNpar) return 0;
3228 return fParams[ipar];
3229}
3230
3231////////////////////////////////////////////////////////////////////////////////
3232/// Return value of parameter named parName.
3233
3235{
3236 const Double_t kNaN = 1e-300;
3238 if (index==-1) {
3239 Error("TFormula", "Parameter %s not found", parName);
3240 return kNaN;
3241 }
3242 return GetParameter(index);
3243}
3244
3245////////////////////////////////////////////////////////////////////////////////
3246/// Return name of one parameter.
3247
3248const char *TFormula::GetParName(Int_t ipar) const
3249{
3250 if (ipar <0 || ipar >= fNpar) return "";
3251 if (fNames[ipar].Length() > 0) return (const char*)fNames[ipar];
3252 return Form("p%d",ipar);
3253}
3254
3255////////////////////////////////////////////////////////////////////////////////
3256/// Return parameter number by name.
3257
3259{
3260 if (!parName)
3261 return -1;
3262
3263 for (Int_t i=0; i<fNpar; i++) {
3264 if (!strcmp(GetParName(i),parName)) return i;
3265 }
3266 return -1;
3267}
3268
3269////////////////////////////////////////////////////////////////////////////////
3270/// Return true if the expression at the index 'oper' has to be treated as a string
3271
3273{
3274 return GetAction(oper) == kStringConst;
3275}
3276
3277////////////////////////////////////////////////////////////////////////////////
3278/// Dump this formula with its attributes.
3279
3281{
3282 Int_t i;
3283 Printf(" %20s : %s Ndim= %d, Npar= %d, Noper= %d",GetName(),GetTitle(), fNdim,fNpar,fNoper);
3284 for (i=0;i<fNoper;i++) {
3285 Printf(" fExpr[%d] = %s action = %d action param = %d ",
3286 i,(const char*)fExpr[i],GetAction(i),GetActionParam(i));
3287 }
3288 //MI change
3289 //
3290 if (fNOperOptimized>0){
3291 Printf("Optimized expression");
3292 for (i=0;i<fNOperOptimized;i++) {
3293 Printf(" fExpr[%d] = %s\t\t action = %d action param = %d ",
3295 }
3296 }
3297
3298 if (!fNames) return;
3299 if (!fParams) return;
3300 for (i=0;i<fNpar;i++) {
3301 Printf(" Par%3d %20s = %g",i,GetParName(i),fParams[i]);
3302 }
3303}
3304
3305////////////////////////////////////////////////////////////////////////////////
3306/// If the formula is for linear fitting, change the title to
3307/// normal and fill the LinearParts array
3308
3310{
3311 TString formula2(formula);
3312 char repl[20];
3313 char *pch;
3315 //replace "++" with "+[i]*"
3316 pch= (char*)strstr(formula.Data(), "++");
3317 if (pch)
3318 formula.Insert(0, "[0]*(");
3319 pch= (char*)strstr(formula.Data(), "++");
3320 if (pch){
3321 //if there are "++", replaces them with +[i]*
3322 nf = 1;
3323 while (pch){
3324 snprintf(repl,20, ")+[%d]*(", nf);
3325 offset = pch-formula.Data();
3326 if (nf<10) replsize = 7;
3327 else if (nf<100) replsize = 8;
3328 else replsize = 9;
3329 formula.Replace(pch-formula.Data(), 2, repl, replsize);
3330 pch = (char*)strstr(formula.Data()+offset, "++");
3331 nf++;
3332 }
3333 formula.Append(')', 1);
3334 } else {
3335 //if there are no ++, create a new string with ++ instead of +[i]*
3336 formula2=formula2(4, formula2.Length()-4);
3337 pch= (char*)strchr(formula2.Data(), '[');
3338 snprintf(repl,20, "++");
3339 nf = 1;
3340 while (pch){
3341 offset = pch-formula2.Data()-1;
3342 if (nf<10) replsize = 5;
3343 else replsize = 6;
3344 formula2.Replace(pch-formula2.Data()-1, replsize, repl, 2);
3345 pch = (char*)strchr(formula2.Data()+offset, '[');
3346 nf++;
3347 }
3348 }
3349
3351 //break up the formula and fill the array of linear parts
3353 formula2 = formula2.ReplaceAll("++", 2, "|", 1);
3354 TObjArray *oa = formula2.Tokenize("|");
3356 for (Int_t i=0; i<nf; i++) {
3357 replaceformula = ((TObjString *)oa->UncheckedAt(i))->GetString();
3358 replaceformula_name = "f_linear_";
3360 TFormula *f = new TFormula(replaceformula_name.Data(), replaceformula.Data());
3361 if (!f) {
3362 Error("TFormula", "f_linear not allocated");
3363 return;
3364 }
3365 {
3367 gROOT->GetListOfFunctions()->Remove(f);
3368 }
3369 f->SetBit(kNotGlobal, true);
3371 }
3372 oa->Delete();
3373}
3374
3375////////////////////////////////////////////////////////////////////////////////
3376/// Initialize parameter number ipar.
3377
3379{
3380 Int_t ipar = GetParNumber(name);
3381 if (ipar <0 || ipar >= fNpar) return;
3382 fParams[ipar] = value;
3383 Update();
3384}
3385
3386////////////////////////////////////////////////////////////////////////////////
3387/// Initialize parameter number ipar.
3388
3390{
3391 if (ipar <0 || ipar >= fNpar) return;
3392 fParams[ipar] = value;
3393 Update();
3394}
3395
3396////////////////////////////////////////////////////////////////////////////////
3397/// Initialize array of all parameters.
3398/// See also the next function with the same name.
3399
3401{
3402 for (Int_t i=0; i<fNpar;i++) {
3403 fParams[i] = params[i];
3404 }
3405 Update();
3406}
3407
3408////////////////////////////////////////////////////////////////////////////////
3409/// Initialize up to 11 parameters
3410/// All arguments except THE FIRST TWO are optional
3411/// In case of a function with only one parameter, call this function with p1=0.
3412/// Minimum two arguments are required to differentiate this function
3413/// from the SetParameters(cont Double_t *params)
3414
3417{
3418 if (fNpar > 0) fParams[0] = p0;
3419 if (fNpar > 1) fParams[1] = p1;
3420 if (fNpar > 2) fParams[2] = p2;
3421 if (fNpar > 3) fParams[3] = p3;
3422 if (fNpar > 4) fParams[4] = p4;
3423 if (fNpar > 5) fParams[5] = p5;
3424 if (fNpar > 6) fParams[6] = p6;
3425 if (fNpar > 7) fParams[7] = p7;
3426 if (fNpar > 8) fParams[8] = p8;
3427 if (fNpar > 9) fParams[9] = p9;
3428 if (fNpar >10) fParams[10]= p10;
3429 Update();
3430}
3431
3432////////////////////////////////////////////////////////////////////////////////
3433/// Set name of parameter number ipar
3434
3435void TFormula::SetParName(Int_t ipar, const char *name)
3436{
3437 if (ipar <0 || ipar >= fNpar) return;
3438 fNames[ipar] = name;
3439}
3440
3441////////////////////////////////////////////////////////////////////////////////
3442/// Set up to 11 parameter names.
3443
3444void TFormula::SetParNames(const char*name0,const char*name1,const char*name2,const char*name3,const char*name4,
3445 const char*name5,const char*name6,const char*name7,const char*name8,const char*name9,const char*name10)
3446{
3447 if (fNpar > 0) fNames[0] = name0;
3448 if (fNpar > 1) fNames[1] = name1;
3449 if (fNpar > 2) fNames[2] = name2;
3450 if (fNpar > 3) fNames[3] = name3;
3451 if (fNpar > 4) fNames[4] = name4;
3452 if (fNpar > 5) fNames[5] = name5;
3453 if (fNpar > 6) fNames[6] = name6;
3454 if (fNpar > 7) fNames[7] = name7;
3455 if (fNpar > 8) fNames[8] = name8;
3456 if (fNpar > 9) fNames[9] = name9;
3457 if (fNpar >10) fNames[10]= name10;
3458}
3459
3460////////////////////////////////////////////////////////////////////////////////
3461/// Stream a class object.
3462
3464{
3465 if (b.IsReading()) {
3466 UInt_t R__s, R__c;
3467 Version_t v = b.ReadVersion(&R__s, &R__c);
3468 if (v==6) {
3469 Error("Streamer","version 6 is not supported");
3470 return;
3471 }
3473
3474 } else {
3475 b.WriteClassBuffer(TFormula::Class(),this);
3476 }
3477}
3478
3479////////////////////////////////////////////////////////////////////////////////
3480/// Stream a class object.
3481
3483{
3484 if (b.IsReading()) {
3485 UInt_t R__s, R__c;
3486 Version_t v = b.ReadVersion(&R__s, &R__c);
3487 if (v==6) {
3488 Error("Streamer","version 6 is not supported");
3489 return;
3490 }
3491 Streamer(b, v, R__s, R__c, nullptr);
3492
3493 } else {
3494 b.WriteClassBuffer(TFormula::Class(),this);
3495 }
3496}
3497
3498////////////////////////////////////////////////////////////////////////////////
3499/// specialized streamer function being able to read old TF1 versions as TF1Old in memory
3500
3502{
3503
3504 //printf("Reading TFormula - version %d \n",v);
3505 if (v > 3 ) {
3506 b.ReadClassBuffer(TFormula::Class(), this, v, R__s, R__c, onfile_class);
3507 if (!TestBit(kNotGlobal)) {
3509 gROOT->GetListOfFunctions()->Add(this);
3510 }
3511
3512 // We need to reinstate (if possible) the TMethodCall.
3513 if (fFunctions.GetLast()>=0) {
3514 // Compiles will reset the parameter values so we need
3515 // to temporarily keep them
3516 Double_t *param = fParams;
3517 TString *names = fNames;
3518 Int_t npar = fNpar;
3519 fParams = nullptr;
3520 fNames = nullptr;
3521 if (Compile()) {
3522 Error("Streamer","error compiling formula");
3523 return;
3524 }
3525 for (Int_t i = 0; i<npar && i<fNpar; ++i) fParams[i] = param[i];
3526 delete [] param;
3527 delete [] fNames;
3528 fNames = names;
3529 } else if (v<6) {
3530 Convert(v);
3531 }
3532 Optimize();
3533 return;
3534 }
3535 // version smaller or equal to 3
3536 // process old versions before automatic schema evolution
3538 b >> fNdim;
3539 b >> fNumber;
3540 if (v > 1) b >> fNval;
3541 if (v > 2) b >> fNstring;
3542 fNpar = b.ReadArray(fParams);
3543 fOper = new Int_t[gMAXOP];
3544 fNoper = b.ReadArray(fOper);
3545 fNconst = b.ReadArray(fConst);
3546 if (fNoper) {
3547 fExpr = new TString[fNoper];
3548 }
3549 if (fNpar) {
3550 fNames = new TString[fNpar];
3551 }
3552 Int_t i;
3553 for (i=0;i<fNoper;i++) fExpr[i].Streamer(b);
3554 for (i=0;i<fNpar;i++) fNames[i].Streamer(b);
3555 {
3557 if (gROOT->GetListOfFunctions()->FindObject(GetName())) return;
3558 gROOT->GetListOfFunctions()->Add(this);
3559 }
3560 b.CheckByteCount(R__s, R__c, TFormula::IsA());
3561
3562 Convert(v);
3563 // end of old versions
3564
3565}
3566
3567void TFormula::Convert(UInt_t /* fromVersion */)
3568{
3569 // Convert the fOper of a TFormula version fromVersion to the current in memory version
3570
3571 enum {
3572 kOldexpo = 1000,
3573 kOldgaus = 2000,
3574 kOldlandau = 4000,
3575 kOldxylandau = 4500,
3576 kOldConstants = 50000,
3577 kOldStrings = 80000,
3578 kOldVariable = 100000,
3579 kOldTreeString = 105000,
3580 kOldFormulaVar = 110000,
3581 kOldBoolOptimize = 120000,
3582 kOldFunctionCall = 200000
3583 };
3584 int i,j;
3585
3586 for (i=0,j=0; i<fNoper; ++i,++j) {
3587 Int_t action = fOper[i];
3588 Int_t newActionCode = 0;
3590
3591 if ( action == 0) {
3592 // Sign Inversion
3593
3595
3596 Float_t aresult = 99.99;
3597 sscanf((const char*)fExpr[i],"%g",&aresult);
3598 R__ASSERT((aresult+1)<0.001);
3599
3600 ++i; // skip the implied multiplication.
3601
3602 // For consistency and for Optimize to work correctly
3603 // we need to remove the "-1" string in fExpr
3604 for (int z=i; z<fNoper; ++z) {
3605 fExpr[z-1] = fExpr[z];
3606 }
3607
3608 } else if ( action < 100 ) {
3609 // basic operators and mathematical library
3610
3612
3613 } else if (action >= kOldFunctionCall) {
3614 // Function call
3615
3618
3619 } else if (action >= kOldBoolOptimize) {
3620 // boolean operation optimizer
3621
3624
3625 } else if (action >= kOldFormulaVar) {
3626 // a variable
3627
3630
3631 } else if (action >= kOldTreeString) {
3632 // a tree string
3633
3636
3637 } else if (action >= kOldVariable) {
3638 // a tree variable
3639
3642
3643 } else if (action == kOldStrings) {
3644 // String
3645
3647
3648 } else if (action >= kOldConstants) {
3649 // numerical value
3650
3653
3654 } else if (action > 10000 && action < kOldConstants) {
3655 // Polynomial
3656
3657 int var = action/10000; //arrondit
3658 newActionCode = kpol + (var-1);
3659 newActionParam = action - var*10000;
3660
3661 } else if (action >= 4600) {
3662
3663 Error("Convert","Unsupported value %d",action);
3664
3665 } else if (action > kOldxylandau) {
3666 // xylandau
3667
3670
3671 } else if (action > kOldlandau) {
3672 // landau, xlandau, ylandau or zlandau
3673
3675 int var = action/100-40;
3676 if (var) newActionCode += var;
3677 newActionParam = action - var*100 - (kOldlandau+1);
3678
3679 } else if (action > 2500 && action < 2600) {
3680 // xygaus
3681
3683 newActionParam = action-2501;
3684
3685 } else if (action > 2000 && action < 2500) {
3686 // gaus, xgaus, ygaus or zgaus
3687
3689 int var = action/100-20;
3690 if (var) newActionCode += var;
3691 newActionParam = action - var*100 - (kOldgaus+1);
3692
3693 } else if (action > 1500 && action < 1600) {
3694 // xyexpo
3695
3697 newActionParam = action-1501;
3698
3699 } else if (action > 1000 && action < 1500) {
3700 // expo or xexpo or yexpo or zexpo
3701
3703 int var = action/100-10;
3704 if (var) newActionCode += var;
3705 newActionParam = action - var*100 - (kOldexpo+1);
3706
3707 } else if (action > 100 && action < 200) {
3708 // Parameter substitution
3709
3711 newActionParam = action - 101;
3712 }
3713
3715
3716 }
3717 if (i!=j) {
3718 fNoper -= (i-j);
3719 }
3720
3721}
3722
3723////////////////////////////////////////////////////////////////////////////////
3724/// TOper offset - helper class for TFormula*
3725/// specify type of operand
3726/// fTypeX = kVariable
3727/// = kParameter
3728/// = kConstant
3729/// fOffestX = offset in corresponding array
3730
3732{
3733 fType0=0;
3734 fType1=0;
3735 fType2=0;
3736 fType3=0;
3737 fOffset0=0;
3738 fOffset1=0;
3739 fOffset2=0;
3740 fOffset3=0;
3741 fOldAction=0;
3742 fToJump=0;
3743}
3744
3745////////////////////////////////////////////////////////////////////////////////
3746/// MakePrimitive
3747/// find TFormulaPrimitive replacement for some operands
3748
3749void TFormula::MakePrimitive(const char *expr, Int_t pos)
3750{
3752 cbase.ReplaceAll("Double_t ","");
3753 int paran = cbase.First("(");
3754 // int nargs = 0;
3755 if (paran>0) {
3756 //nargs = 1;
3757 cbase[paran]=0;
3758 }
3759
3760 if (cbase=="<") cbase="XlY";
3761 if (cbase=="<=") cbase="XleY";
3762 if (cbase==">") cbase="XgY";
3763 if (cbase==">=") cbase="XgeY";
3764 if (cbase=="==" && GetActionOptimized(pos)!=kStringEqual) cbase="XeY";
3765 if (cbase=="!=" && GetActionOptimized(pos)!=kStringNotEqual) cbase="XneY";
3766
3768 if (prim) {
3769 fPredefined[pos] = prim;
3770 if (prim->fType==10) {
3772 }
3773 if (prim->fType==110) {
3775 }
3776 if (prim->fType==1110) {
3778 }
3779 if (prim->fType==-1) {
3781 }
3782 if (prim->fType==0){
3784 fConst[fNconst] = prim->Eval(nullptr);
3785 fNconst++;
3786 }
3787 return;
3788 }
3789}
3790
3791////////////////////////////////////////////////////////////////////////////////
3792/// MI include
3793///
3794/// Optimize formula
3795/// - Minimize the number of operands
3796/// 1. several operands are glued together
3797/// 2. some primitive functions glued together - exemp. (x+y) => PlusXY(x,y)
3798/// 3. maximize number of standard calls minimizing number of jumps in Eval cases
3799/// 4. variables, parameters and constants are mapped - using fOperOfssets0
3800/// Eval procedure use direct acces to data (only one corresponding case statement in eval procedure)
3801/// ~~~ {.cpp}
3802/// pdata[operand={Var,Par,Const}][offset]
3803/// pdata[fOperOffsets0[i]][fOperOffset1[i+1]]
3804/// ~~~
3805/// - The fastest evaluation function is chosen at the end
3806/// 1. fOptimal := pointer to the fastest function for given evaluation string
3807/// ~~~ {.cpp}
3808/// switch(GetActionOptimized(0)){
3809/// case kData : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive0; break;}
3810/// case kUnary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive1; break;}
3811/// case kBinary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive2; break;}
3812/// case kThree : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive3; break;}
3813/// case kFDM : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive4; break;}
3814/// }
3815/// ~~~
3816/// 2. ex.
3817/// - fOptimal = TFormula::EvalPrimitive0 - if it return only variable, constant or parameter
3818/// - = TFormula::EvalPrimitive1 - if only one unary operation
3819/// - = TFormula::EvalPrimitive2 - if only one binary operation
3820
3822{
3823 //
3824 // Initialize data members
3825 //
3826
3827 Int_t i;
3828
3829 if (fPredefined) { delete [] fPredefined; fPredefined = nullptr;}
3830 if (fOperOffset) { delete [] fOperOffset; fOperOffset = nullptr;}
3831 if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = nullptr;}
3832 if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = nullptr;}
3833
3838 for (i=0; i<fNoper; i++) {
3839 fExprOptimized[i] = fExpr[i] ;
3840 fOperOptimized[i] = fOper[i];
3841 fPredefined[i]= nullptr;
3842 }
3843
3844 //
3845 //Make primitives
3846 //
3847 for (i=0;i<fNoper;i++){
3848 if (fExprOptimized[i].Data()) {
3849 MakePrimitive(fExprOptimized[i].Data(), i);
3850 }
3851 }
3852 //
3853 Int_t maxfound = fNoper+1;
3854 Int_t *offset = new Int_t[maxfound*16];
3855 Int_t *optimized = new Int_t[maxfound];
3856 //
3857 //
3869 //
3870 // set data pointers
3871 //
3872 for (i=0;i<fNoper;i++) optimized[i]=0;
3873 //
3874 for (i=0;i<fNoper;i++){
3877
3878 if (action==kBoolOptimize){
3879 //
3880 // optimize booleans
3881 //
3882 fOperOffset[i].fType1 = actionparam/10; // operands to skip
3883 fOperOffset[i].fOffset0 = actionparam%10; // 1 is && , 2 is || - operand
3884 fOperOffset[i].fToJump = i+fOperOffset[i].fType1; // where we should jump
3885 continue;
3886 }
3887 if (action==kJump || action==kJumpIf) {
3888 // Ternary conditional operator
3891 }
3892 //
3893 if (action==kConstant&&i<fNoper-2){
3894 //
3895 // get offsets for kFDM operands
3896 //
3898 optimized[i]=1;
3899 optimized[i+1]=1;
3900 i+=2;
3903 Int_t offset2 = int(fConst[fOperOffset[i].fOffset0]+0.4);
3906 if (nparmax>fNpar){ // increase expected number of parameters
3907 fNpar=nparmax;
3908 }
3909 continue;
3910 }
3911 }
3912 switch(action){
3913 case kVariable : {action=kData; fOperOffset[i].fType0=0; break;}
3914 case kParameter: {action=kData; fOperOffset[i].fType0=1; break;}
3915 case kConstant : {action=kData; fOperOffset[i].fType0=2; break;}
3916 }
3917 //
3919 SetActionOptimized(i,action, actionparam); //set common data option
3920 }
3921 //
3922 //
3924 //
3925 for (i=0; i<fNoper; ++i)
3926 {
3927 //
3928 if (!(GetActionOptimized(i)== kData)) continue;
3929 offset[0] = fOperOffset[i].fType0; //
3930 offset[1] = fOperOptimized[i] & kTFOperMask; // offset
3931
3932 if ((i+1) >= fNoper) continue;
3933
3934 if (GetActionOptimized(i+1)==kFD1){
3935 optimized[i] = 1; // to be optimized
3936 i++;
3937 fOperOffset[i].fType0 = offset[0];
3938 fOperOffset[i].fOffset0 = offset[1];
3940 continue;
3941 }
3942 if (GetActionOptimized(i+1)==kAdd){
3943 optimized[i] = 1; // to be optimized
3944 i++;
3945 fOperOffset[i].fType0 = offset[0];
3946 fOperOffset[i].fOffset0 = offset[1];
3948 continue;
3949 }
3950 if (GetActionOptimized(i+1)==kMultiply){
3951 optimized[i] = 1; // to be optimized
3952 i++;
3953 fOperOffset[i].fType0 = offset[0];
3954 fOperOffset[i].fOffset0 = offset[1];
3956 continue;
3957 }
3958
3959 if ((i+2) >= fNoper) continue;
3960
3961 //
3962 //Binary operators
3963 if (!(GetActionOptimized(i+1)== kData)) continue;
3964 offset[2] = fOperOffset[i+1].fType0;
3965 offset[3] = fOperOptimized[i+1] & kTFOperMask; // offset
3966 //
3969
3970 optimized[i] = 1; // to be optimized
3971 optimized[i+1] = 1; // to be optimized
3972 i+=2;
3973 //
3974 fOperOffset[i].fType0 = offset[0];
3975 fOperOffset[i].fOffset0 = offset[1];
3976 fOperOffset[i].fType1 = offset[2];
3977 fOperOffset[i].fOffset1 = offset[3];
3978 fOperOffset[i].fType2 = GetActionOptimized(i); //remember old action
3979 if (GetActionOptimized(i)==kAdd) {fPredefined[i] = primitive[0];}
3981 if (GetActionOptimized(i)==kMultiply) {
3982 fPredefined[i]=primitive[2];
3983 if (offset[0]==offset[2]&&offset[1]==offset[3]) {
3984 fPredefined[i] = primitive[8];
3986 continue;
3987 }
3988 }
3989 if (GetActionOptimized(i)==kDivide) {
3990 fPredefined[i] = primitive[3];
3991 }
3993 continue;
3994 }
3995
3996 if ((i+3) >= fNoper) continue;
3997
3998 //
3999 //operator 3
4000 //
4001 if (!(GetActionOptimized(i+2)== kData)) continue;
4002 offset[4] = fOperOffset[i+2].fType0;
4003 offset[5] = fOperOptimized[i+2] & kTFOperMask; // offset
4004 //
4007 optimized[i+0] = 1; // to be optimized
4008 optimized[i+1] = 1; // to be optimized
4009 optimized[i+2] = 1; // to be optimized
4010 i+=3;
4011 //
4012 fOperOffset[i].fType0 = offset[0];
4013 fOperOffset[i].fOffset0 = offset[1];
4014 fOperOffset[i].fType1 = offset[2];
4015 fOperOffset[i].fOffset1 = offset[3];
4016 fOperOffset[i].fType2 = offset[4];
4017 fOperOffset[i].fOffset2 = offset[5];
4018 //
4019 fOperOffset[i].fOldAction = GetActionOptimized(i); //remember old action
4020 if (GetActionOptimized(i)==kFD3) {
4022 continue;
4023 }
4024 Int_t action=0;
4028 action=5;
4029 if (offset[0]==offset[2]&&offset[1]==offset[3]&&offset[0]==offset[4]&&offset[1]==offset[5]){
4030 fPredefined[i]=primitive[9];
4032 action =9;
4033 }
4034 }
4037 //
4038 optimized[i]=1;
4039 i++;
4040 fOperOffset[i].fType0 = offset[0];
4041 fOperOffset[i].fOffset0 = offset[1];
4042 fOperOffset[i].fType1 = offset[2];
4043 fOperOffset[i].fOffset1 = offset[3];
4044 fOperOffset[i].fType2 = offset[4];
4045 fOperOffset[i].fOffset2 = offset[5];
4048 continue;
4049 }
4050 }
4051 //
4052 //
4053 Int_t operO=0;
4054 TString expr="";
4055 Int_t *map0 = new Int_t[maxfound]; //remapping of the operands
4056 Int_t *map1 = new Int_t[maxfound]; //remapping of the operands
4057 for (i=0;i<fNoper;i++){
4058 map0[i] = operO;
4059 map1[operO] = i;
4063 expr += fExprOptimized[i];
4064 if (optimized[i]==0){
4066 expr = "";
4067 operO++;
4068 }else{
4069 expr += ",";
4070 }
4071 }
4072 //
4073 // Recalculate long jump for Boolean optimize
4074 //
4075 for (i=0; i<fNOperOptimized; i++){
4080 fOperOffset[i].fToJump = newpos; // new position to jump
4082 switch (actionop) {
4083 case 1: SetActionOptimized(i,kBoolOptimizeAnd,newpos); break;
4084 case 2: SetActionOptimized(i,kBoolOptimizeOr,newpos); break;
4085 }
4086 } else if (optaction==kJump || optaction==kJumpIf) {
4089 fOperOffset[i].fToJump = newpos; // new position to jump
4091 }
4092 }
4093
4094
4096 //
4098 if (fNOperOptimized==1) {
4099 switch(GetActionOptimized(0)){
4105 }
4106 }
4107
4108 delete [] map1;
4109 delete [] map0;
4110 delete [] offset;
4111 delete [] optimized;
4112}
4113
4114////////////////////////////////////////////////////////////////////////////////
4115/// Evaluate primitive formula
4116
4118{
4119 const Double_t *pdata[3] = {x,(params!=nullptr)?params:fParams, fConst};
4121 switch((fOperOptimized[0] >> kTFOperShift)) {
4122 case kData : return result;
4123 case kUnary : return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
4124 case kBinary :return (fPredefined[0]->fFunc110)(result,
4126
4127 case kThree :return (fPredefined[0]->fFunc1110)(result, pdata[fOperOffset->fType1][fOperOffset->fOffset1],
4129 case kFDM : return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
4130 (Double_t*)&params[fOperOffset->fOffset0]);
4131 }
4132 return 0;
4133}
4134
4135////////////////////////////////////////////////////////////////////////////////
4136/// Evaluate primitive formula
4137
4139{
4140 const Double_t *pdata[3] = {x,(params!=nullptr)?params:fParams, fConst};
4142}
4143
4144////////////////////////////////////////////////////////////////////////////////
4145/// Evaluate primitive formula
4146
4148{
4149 const Double_t *pdata[3] = {x,(params!=nullptr)?params:fParams, fConst};
4150 return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
4151}
4152
4153////////////////////////////////////////////////////////////////////////////////
4154/// Evaluate primitive formula
4155
4157{
4158 const Double_t *pdata[3] = {x,(params!=nullptr)?params:fParams, fConst};
4159 return (fPredefined[0]->fFunc110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0],
4161}
4162
4163////////////////////////////////////////////////////////////////////////////////
4164/// Evaluate primitive formula
4165
4167{
4168 const Double_t *pdata[3] = {x,(params!=nullptr)?params:fParams, fConst};
4171}
4172
4173////////////////////////////////////////////////////////////////////////////////
4174/// Evaluate primitive formula
4175
4177{
4178 const Double_t *par = (params!=nullptr)?params:fParams;
4179 return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
4180 (Double_t*)&par[fOperOffset->fOffset0]);
4181}
4182
4183////////////////////////////////////////////////////////////////////////////////
4184/// Evaluate this formula.
4185///
4186/// The current value of variables x,y,z,t is passed through the pointer x.
4187/// The parameters used will be the ones in the array params if params is given
4188/// otherwise parameters will be taken from the stored data members fParams
4189///
4190/// \image html TFormula_eval.png
4191
4193{
4194 const Double_t *pdata[3] = {x,(uparams!=nullptr)?uparams:fParams, fConst};
4195 //
4196 Int_t i,j;
4197 Double_t tab[kMAXFOUND] = {0};
4198 const char *stringStack[gMAXSTRINGFOUND] = {nullptr};
4200 char *string_calc[gMAXSTRINGFOUND] = {nullptr};
4201 Int_t precalculated = 0;
4203
4204 Double_t *params;
4205
4206 if (uparams) {
4207 //for (j=0;j<fNpar;j++) fParams[j] = params[j];
4208 params = const_cast<Double_t*>(uparams);
4209 } else {
4210 params = fParams;
4211 }
4212
4213 //if (params) {
4214 // for (j=0;j<fNpar;j++) fParams[j] = params[j];
4215 //}
4216 UInt_t pos = 0;
4217 UInt_t strpos = 0;
4218 // for (i=0; i<fNoper; ++i) {
4219 for (i=0; i<fNOperOptimized; ++i) {
4220 //
4221 const int oper = fOperOptimized[i];
4222 const int opcode = oper >> kTFOperShift;
4223
4224 switch(opcode) { // FREQUENTLY USED OPERATION
4225 case kData : tab[pos] = pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; pos++;continue;
4226 case kPlusD : tab[pos-1]+= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
4227 case kMultD : tab[pos-1]*= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
4228 case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
4229 case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
4230 case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
4231 case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
4232 else tab[pos-1] /= tab[pos];
4233 continue;
4234 case kUnary : tab[pos] = (fPredefined[i]->fFunc10)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]); pos++;continue;
4235 case kBinary : tab[pos] = (fPredefined[i]->fFunc110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
4236 pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1]);pos++;continue;
4237
4238 case kThree : tab[pos] = (fPredefined[i]->fFunc1110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
4239 pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1],
4240 pdata[fOperOffset[i].fType2][fOperOffset[i].fOffset2]); pos++; continue;
4241
4242 case kFDM : tab[pos] = (fPredefined[i]->fFuncG)(&x[fOperOffset[i].fType0],&params[fOperOffset[i].fOffset0]); pos++;continue;
4243 case kFD1 : tab[pos-1] =(fPredefined[i]->fFunc10)(tab[pos-1]); continue;
4244 case kFD2 : pos--; tab[pos-1] = (fPredefined[i]->fFunc110)(tab[pos-1],tab[pos]); continue;
4245 case kFD3 : pos-=2; tab[pos-1] = (fPredefined[i]->fFunc1110)(tab[pos-1],tab[pos],tab[pos+1]); continue;
4246 }
4247 //
4248 switch(opcode) {
4249 case kBoolOptimizeAnd: {
4250 if (!tab[pos-1]) i=fOperOffset[i].fToJump;
4251 continue;
4252 }
4253 case kBoolOptimizeOr: {
4254 if (tab[pos-1]) i=fOperOffset[i].fToJump;
4255 continue;
4256 }
4257 case kAnd : pos--; tab[pos-1] = (bool)tab[pos]; continue; // use the fact that other were check before - see bool optimize
4258 case kOr : pos--; tab[pos-1] = (bool)tab[pos]; continue;
4259 }
4260 switch(opcode) {
4261 // case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
4262 case kabs : if (tab[pos-1]<0) tab[pos-1]=-tab[pos-1]; continue;
4263 case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
4264 case kint : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
4265 case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
4266
4267 case kModulo : {pos--;
4268 Long64_t int1((Long64_t)tab[pos-1]);
4269 Long64_t int2((Long64_t)tab[pos]);
4270 tab[pos-1] = Double_t(int1%int2);
4271 continue;}
4272
4273
4274 case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExprOptimized[i].Data(); pos++; tab[pos-1] = 0; continue; }
4275 case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
4276
4277 case kstrstr : strpos -= 2; pos-=2; pos++;
4278 if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
4279 else tab[pos-1]=0;
4280 continue;
4281 case kpi : pos++; tab[pos-1] = TMath::Pi(); continue;
4282
4283
4284 case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
4285
4286 case krndm : pos++; tab[pos-1] = gRandom->Rndm(); continue;
4287
4288
4289 case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
4290 else tab[pos-1]=0;
4291 continue;
4292 case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
4293 else tab[pos-1]=0;
4294 continue;
4295 case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1;
4296 continue;
4297
4298 case kStringEqual : strpos -= 2; pos -=2 ; pos++;
4299 if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
4300 else tab[pos-1]=0;
4301 continue;
4302 case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
4303 if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
4304 else tab[pos-1]=0;
4305 continue;
4306
4307 case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
4308 case kBitOr : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
4309 case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
4310 case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
4311
4312 case kJump : i = (oper & kTFOperMask); continue;
4313 case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
4314
4315 case kBoolOptimize: {
4316 // boolean operation optimizer
4317
4318 int param = (oper & kTFOperMask);
4319 int op = param % 10; // 1 is && , 2 is ||
4320
4321 if (op == 1 && (!tab[pos-1]) ) {
4322 // &&: skip the right part if the left part is already false
4323
4324 i += param / 10;
4325
4326 // Preserve the existing behavior (i.e. the result of a&&b is
4327 // either 0 or 1)
4328 tab[pos-1] = 0;
4329
4330 } else if (op == 2 && tab[pos-1] ) {
4331 // ||: skip the right part if the left part is already true
4332
4333 i += param / 10;
4334
4335 // Preserve the existing behavior (i.e. the result of a||b is
4336 // either 0 or 1)
4337 tab[pos-1] = 1;
4338
4339 }
4340
4341 continue;
4342 }
4343
4344 }
4345 switch(opcode) {
4346
4347#define R__EXPO(var) \
4348 { \
4349 pos++; int param = (oper & kTFOperMask); \
4350 tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]); \
4351 continue; \
4352 }
4353 // case kexpo:
4354 case kxexpo: R__EXPO(0);
4355 case kyexpo: R__EXPO(1);
4356 case kzexpo: R__EXPO(2);
4357 case kxyexpo:{ pos++; int param = (oper & kTFOperMask);
4358 tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
4359 continue; }
4360#ifdef R__GAUS
4361#undef R__GAUS
4362#endif
4363#define R__GAUS(var) \
4364 { \
4365 pos++; int param = (oper & kTFOperMask); \
4366 tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1], \
4367 params[param+2],IsNormalized()); \
4368 continue; \
4369 }
4370
4371 // case kgaus:
4372 case kxgaus: R__GAUS(0);
4373 case kygaus: R__GAUS(1);
4374 case kzgaus: R__GAUS(2);
4375 case kxygaus: { pos++; int param = (oper & kTFOperMask);
4377 if (params[param+2] == 0) {
4378 intermede1=1e10;
4379 } else {
4380 intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
4381 }
4383 if (params[param+4] == 0) {
4384 intermede2=1e10;
4385 } else {
4386 intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
4387 }
4388 tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
4389 continue; }
4390
4391#define R__LANDAU(var) \
4392 { \
4393 pos++; const int param = (oper & kTFOperMask); \
4394 tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
4395 continue; \
4396 }
4397 // case klandau:
4398 case kxlandau: R__LANDAU(0);
4399 case kylandau: R__LANDAU(1);
4400 case kzlandau: R__LANDAU(2);
4401 case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
4402 Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
4403 Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
4404 tab[pos-1] = params[param]*intermede1*intermede2;
4405 continue;
4406 }
4407
4408#define R__POLY(var) \
4409 { \
4410 pos++; int param = (oper & kTFOperMask); \
4411 tab[pos-1] = 0; Double_t intermede = 1; \
4412 Int_t inter = param/100; /* arrondit */ \
4413 Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
4414 for (j=0 ;j<inter+1;j++) { \
4415 tab[pos-1] += intermede*params[j+int1]; \
4416 intermede *= x[var]; \
4417 } \
4418 continue; \
4419 }
4420 // case kpol:
4421 case kxpol: R__POLY(0);
4422 case kypol: R__POLY(1);
4423 case kzpol: R__POLY(2);
4424
4425 case kDefinedVariable : {
4426 if (!precalculated) {
4427 precalculated = 1;
4428 for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
4429 }
4430 pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
4431 continue;
4432 }
4433
4434 case kDefinedString : {
4435 int param = (oper & kTFOperMask);
4436 if (!precalculated_str) {
4438 for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
4439 }
4440 strpos++; stringStack[strpos-1] = string_calc[param];
4441 pos++; tab[pos-1] = 0;
4442 continue;
4443 }
4444
4445 case kFunctionCall: {
4446 // an external function call
4447
4448 int param = (oper & kTFOperMask);
4449 int fno = param / 1000;
4450 int nargs = param % 1000;
4451
4452 // Retrieve the function
4454
4455 // Set the arguments
4456 method->ResetParam();
4457 if (nargs) {
4458 UInt_t argloc = pos-nargs;
4459 for(j=0;j<nargs;j++,argloc++,pos--) {
4460 method->SetParam(tab[argloc]);
4461 }
4462 }
4463 pos++;
4464 Double_t ret;
4465 method->Execute(ret);
4466 tab[pos-1] = ret; // check for the correct conversion!
4467
4468 continue;
4469 };
4470 }
4473 Warning("EvalParFast","Found an unsupported optmized opcode (%d)",oper >> kTFOperShift);
4474 }
4475 }
4476 Double_t result0 = tab[0];
4477 return result0;
4478
4479}
4480
4481////////////////////////////////////////////////////////////////////////////////
4482/// Pre compile function
4483
4485{
4486 TString str = fTitle;
4487 if (str.Length()<3) return 1;
4488 if (str[str.Length()-1]!='+'&&str[str.Length()-2]!='+') return 1;
4489 str[str.Length()-2]=0;
4490 TString funName("preformula_");
4491 funName += fName;
4493 TString fileName;
4494 fileName.Form("/tmp/%s.C",funName.Data());
4495
4496 FILE *hf;
4497 hf = fopen(fileName.Data(),"w");
4498 if (hf == nullptr) {
4499 Error("PreCompile","Unable to open the file %s for writing.",fileName.Data());
4500 return 1;
4501 }
4502 fprintf(hf, "/////////////////////////////////////////////////////////////////////////\n");
4503 fprintf(hf, "// This code has been automatically generated \n");
4504 //
4505 fprintf(hf, "Double_t %s(Double_t *x, Double_t *p){",funName.Data());
4506 fprintf(hf, "return (%s);\n}",str.Data());
4507
4508 // fprintf("ROOT::v5::TFormulaPrimitive::AddFormula(new ROOT::v5::TFormulaPrimitive(\"%s::%s\",\"%s::%s\",(ROOT::v5::TFormulaPrimitive::GenFunc0)%s::%s));\n",
4509 // clname,method->GetName(),clname,method->GetName(),clname,method->GetName());
4510 fclose(hf);
4511
4512 return 0;
4513
4514
4515}
4516
4517////////////////////////////////////////////////////////////////////////////////
4518/// static function to set the maximum value of 3 parameters
4519///
4520/// - maxop : maximum number of operations
4521/// - maxpar : maximum number of parameters
4522/// - maxconst : maximum number of constants
4523///
4524/// None of these parameters cannot be less than 10 (default is 1000)
4525/// call this function to increase one or all maxima when processing
4526/// very complex formula, eg TFormula::SetMaxima(100000,1000,1000000);
4527/// If you process many functions with a small number of operations/parameters
4528/// you may gain some memory and performance by decreasing these values.
4529
4536
4537////////////////////////////////////////////////////////////////////////////////
4538/// static function to get the maximum value of 3 parameters
4539/// -maxop : maximum number of operations
4540/// -maxpar : maximum number of parameters
4541/// -maxconst : maximum number of constants
4542
4549
4550 } // end namespace v5
4551
4552} // 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
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:374
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#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
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 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:84
ClassInfo_t * GetClassInfo() const
Definition TClass.h:440
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:3069
Method or function calling interface.
Definition TMethodCall.h:37
static const EReturnType kOther
Definition TMethodCall.h:46
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:174
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
void Streamer(TBuffer &) override
Stream an object of class TObject.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
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
Mother of all ROOT objects.
Definition TObject.h:41
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:205
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:421
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:864
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
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
const char * Data() const
Definition TString.h:376
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:616
Double_t ACos(Double_t)
Returns the principal value of the arc cosine of x, expressed in radians.
Definition TMath.h:636
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:628
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:713
Double_t ATan(Double_t)
Returns the principal value of the arc tangent of x, expressed in radians.
Definition TMath.h:644
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:622
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:650
Double_t Log(Double_t x)
Returns the natural logarithm of x.
Definition TMath.h:760
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:666
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:725
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:598
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:592
Double_t Tan(Double_t)
Returns the tangent of an angle of x radians.
Definition TMath.h:604
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:766
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:610
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