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