%%cpp -d template class KahanSum final : public ROOT::Detail::RDF::RActionImpl> { public: /// This type is a requirement for every helper. using Result_t = T; private: std::vector fPartialSums; std::vector fCompensations; int fNSlots; std::shared_ptr fResultSum; void KahanAlgorithm(const T &x, T &sum, T &compensation){ T y = x - compensation; T t = sum + y; compensation = (t - sum) - y; sum = t; } public: KahanSum(KahanSum &&) = default; KahanSum(const KahanSum &) = delete; KahanSum(const std::shared_ptr &r) : fResultSum(r) { static_assert(std::is_floating_point::value, "Kahan sum makes sense only on floating point numbers"); fNSlots = ROOT::IsImplicitMTEnabled() ? ROOT::GetThreadPoolSize() : 1; fPartialSums.resize(fNSlots, 0.); fCompensations.resize(fNSlots, 0.); } std::shared_ptr GetResultPtr() const { return fResultSum; } void Initialize() {} void InitTask(TTreeReader *, unsigned int) {} void Exec(unsigned int slot, T x) { KahanAlgorithm(x, fPartialSums[slot], fCompensations[slot]); } template ::value, int> = 0> void Exec(unsigned int slot, const T &vs) { for (auto &&v : vs) { Exec(slot, v); } } void Finalize() { T sum(0) ; T compensation(0); for (int i = 0; i < fNSlots; ++i) { KahanAlgorithm(fPartialSums[i], sum, compensation); } *fResultSum = sum; } std::string GetActionName() { return "KahanSum"; } }; ROOT::EnableImplicitMT(2); ROOT::RDataFrame d(20); auto dd = d.Define("x", "(rdfentry_ %2 == 0) ? 0.00000001 : 100000000."); auto ptr = std::make_shared(); KahanSum helper(ptr); auto kahanResult = dd.Book(std::move(helper), {"x"}); auto plainResult = dd.Sum({"x"}); std::cout << std::setprecision(24) << "Kahan: " << *kahanResult << " Classical: " << *plainResult << std::endl; gROOT->GetListOfCanvases()->Draw()