Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
df022_useKahan.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_dataframe
3 /// \notebook
4 /// This tutorial shows how to implement a Kahan summation custom action.
5 ///
6 /// \macro_code
7 /// \macro_output
8 ///
9 /// \date July 2018
10 /// \author Enrico Guiraud, Danilo Piparo, Massimo Tumolo
11 
12 template <typename T>
13 class KahanSum final : public ROOT::Detail::RDF::RActionImpl<class KahanSum<T>> {
14 public:
15  /// This type is a requirement for every helper.
16  using Result_t = T;
17 
18 private:
19  std::vector<T> fPartialSums;
20  std::vector<T> fCompensations;
21  int fNSlots;
22 
23  std::shared_ptr<T> fResultSum;
24 
25  void KahanAlgorithm(const T &x, T &sum, T &compensation){
26  T y = x - compensation;
27  T t = sum + y;
28  compensation = (t - sum) - y;
29  sum = t;
30  }
31 
32 public:
33  KahanSum(KahanSum &&) = default;
34  KahanSum(const KahanSum &) = delete;
35 
36  KahanSum(const std::shared_ptr<T> &r) : fResultSum(r)
37  {
38  static_assert(std::is_floating_point<T>::value, "Kahan sum makes sense only on floating point numbers");
39 
40  fNSlots = ROOT::IsImplicitMTEnabled() ? ROOT::GetImplicitMTPoolSize() : 1;
41  fPartialSums.resize(fNSlots, 0.);
42  fCompensations.resize(fNSlots, 0.);
43  }
44 
45  std::shared_ptr<Result_t> GetResultPtr() const { return fResultSum; }
46 
47  void Initialize() {}
48  void InitTask(TTreeReader *, unsigned int) {}
49 
50  void Exec(unsigned int slot, T x)
51  {
52  KahanAlgorithm(x, fPartialSums[slot], fCompensations[slot]);
53  }
54 
55  template <typename V=T, typename std::enable_if<ROOT::TypeTraits::IsContainer<V>::value, int>::type = 0>
56  void Exec(unsigned int slot, const T &vs)
57  {
58  for (auto &&v : vs) {
59  Exec(slot, v);
60  }
61  }
62 
63  void Finalize()
64  {
65  T sum(0) ;
66  T compensation(0);
67  for (int i = 0; i < fNSlots; ++i) {
68  KahanAlgorithm(fPartialSums[i], sum, compensation);
69  }
70  *fResultSum = sum;
71  }
72 
73  std::string GetActionName(){
74  return "THnHelper";
75  }
76 
77 };
78 
79 void df022_useKahan()
80 {
81  // We enable implicit parallelism
82  ROOT::EnableImplicitMT(2);
83 
84  ROOT::RDataFrame d(20);
85  auto dd = d.Define("x", "(rdfentry_ %2 == 0) ? 0.00000001 : 100000000.");
86 
87  auto ptr = std::make_shared<double>();
88  KahanSum<double> helper(ptr);
89 
90  auto kahanResult = dd.Book<double>(std::move(helper), {"x"});
91  auto plainResult = dd.Sum<double>({"x"});
92 
93  std::cout << std::setprecision(24) << "Kahan: " << *kahanResult << " Classical: " << *plainResult << std::endl;
94  // Outputs: Kahan: 1000000000.00000011920929 Classical: 1000000000
95 }