Skip to content

Commit 9d4425e

Browse files
committed
[hist] Always use maximum floating point precision in GetExpFormula
In #18194, an optional parameter to `TFormula::GetExpFormula()` was introduced, which can be used to customize the precision when putting parameters into the jitted code. However, I don't see the reason why wouldn't like to always print the floating point numbers with maximum precision, which is suggested in this commit. This is achieved using modern C++ functions, which are also not respecting the users locale setting, but instead use the classic C locale by default, which is what we need when generating code. Follows up on #18194 (and its partial revert #18216). Closes #17225. Replaces #17327.
1 parent 3b55581 commit 9d4425e

File tree

3 files changed

+27
-17
lines changed

3 files changed

+27
-17
lines changed

hist/hist/inc/TFormula.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class TFormula : public TNamed
248248
#ifdef R__HAS_VECCORE
249249
ROOT::Double_v EvalParVec(const ROOT::Double_v *x, const Double_t *params = nullptr) const;
250250
#endif
251-
TString GetExpFormula(Option_t *option = "", const char *fl_format = "%g") const;
251+
TString GetExpFormula(Option_t *option = "") const;
252252
TString GetGradientFormula() const;
253253
TString GetHessianFormula() const;
254254
TString GetUniqueFuncName() const {

hist/hist/src/TFormula.cxx

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
#include "ROOT/StringUtils.hxx"
2424

2525
#include <array>
26+
#include <functional>
27+
#include <iomanip>
2628
#include <iostream>
29+
#include <limits>
2730
#include <memory>
28-
#include <unordered_map>
29-
#include <functional>
3031
#include <set>
3132
#include <sstream>
33+
#include <unordered_map>
3234

3335
using std::map, std::pair, std::make_pair, std::list, std::max, std::string;
3436

@@ -39,6 +41,17 @@ using std::map, std::pair, std::make_pair, std::list, std::max, std::string;
3941

4042
ClassImp(TFormula);
4143

44+
namespace {
45+
46+
std::string doubleToString(double val)
47+
{
48+
std::stringstream ss;
49+
ss << std::setprecision(std::numeric_limits<double>::max_digits10) << val;
50+
return ss.str();
51+
}
52+
53+
} // namespace
54+
4255
/** \class TFormula TFormula.h "inc/TFormula.h"
4356
\ingroup Hist
4457
The Formula class
@@ -2341,8 +2354,7 @@ void TFormula::ProcessFormula(TString &formula)
23412354
map<TString, Double_t>::iterator constIt = fConsts.find(fun.GetName());
23422355
if (constIt != fConsts.end()) {
23432356
TString pattern = TString::Format("{%s}", fun.GetName());
2344-
TString value = TString::Format("%lf", (*constIt).second);
2345-
formula.ReplaceAll(pattern, value);
2357+
formula.ReplaceAll(pattern, doubleToString(constIt->second));
23462358
fun.fFound = true;
23472359
// std::cout << "constant with name " << fun.GetName() << " is found " << std::endl;
23482360
continue;
@@ -3606,12 +3618,8 @@ void TFormula::ReInitializeEvalMethod() {
36063618
/// - If option = "P" replace the parameter names with their values
36073619
/// - If option = "CLING" return the actual expression used to build the function passed to cling
36083620
/// - If option = "CLINGP" replace in the CLING expression the parameter with their values
3609-
/// @param fl_format specifies the printf floating point precision when option
3610-
/// contains "p". Default is `%g` (6 decimals). If you need more precision,
3611-
/// change e.g. to `%.9f`, or `%a` for a lossless representation.
3612-
/// @see https://cplusplus.com/reference/cstdio/printf/
36133621

3614-
TString TFormula::GetExpFormula(Option_t *option, const char *fl_format) const
3622+
TString TFormula::GetExpFormula(Option_t *option) const
36153623
{
36163624
TString opt(option);
36173625
if (opt.IsNull() || TestBit(TFormula::kLambda) ) return fFormula;
@@ -3647,9 +3655,10 @@ TString TFormula::GetExpFormula(Option_t *option, const char *fl_format) const
36473655
TString parNumbName = clingFormula(i+2,j-i-2);
36483656
int parNumber = parNumbName.Atoi();
36493657
assert(parNumber < fNpar);
3650-
TString replacement = TString::Format(fl_format, GetParameter(parNumber));
3651-
clingFormula.Replace(i,j-i+1, replacement );
3652-
i += replacement.Length();
3658+
std::stringstream ss;
3659+
std::string replacement = doubleToString(GetParameter(parNumber));
3660+
clingFormula.Replace(i,j-i+1, replacement);
3661+
i += replacement.size();
36533662
}
36543663
i++;
36553664
}
@@ -3669,9 +3678,10 @@ TString TFormula::GetExpFormula(Option_t *option, const char *fl_format) const
36693678
return expFormula;
36703679
}
36713680
TString parName = expFormula(i+1,j-i-1);
3672-
TString replacement = TString::Format(fl_format, GetParameter(parName));
3673-
expFormula.Replace(i,j-i+1, replacement );
3674-
i += replacement.Length();
3681+
std::stringstream ss;
3682+
std::string replacement = doubleToString(GetParameter(parName));
3683+
expFormula.Replace(i,j-i+1, replacement);
3684+
i += replacement.size();
36753685
}
36763686
i++;
36773687
}

test/TFormulaParsingTests.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ bool test16() {
308308
// test GetExpFormula
309309
TFormula f("f","[2] + [0]*x + [1]*x*x");
310310
f.SetParameters(1,2,3);
311-
return (f.GetExpFormula("CLING P", "%f") == TString("3.000000+1.000000*x[0]+2.000000*x[0]*x[0] "));
311+
return (f.GetExpFormula("CLING P") == TString("3+1*x[0]+2*x[0]*x[0] "));
312312
}
313313

314314
bool test17() {

0 commit comments

Comments
 (0)