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