@@ -91,6 +91,14 @@ struct LeftFoldReduce
9191 m_accumulated_value = m_op (std::move (m_accumulated_value), std::move (val));
9292 }
9393
94+ /* !
95+ \brief combine a value into the reducer
96+ */
97+ RAJA_HOST_DEVICE RAJA_INLINE void operator +=(T val)
98+ {
99+ combine (std::move (val));
100+ }
101+
94102private:
95103 BinaryOp m_op;
96104 T m_accumulated_value;
@@ -214,6 +222,14 @@ struct BinaryTreeReduce
214222 ++m_count;
215223 }
216224
225+ /* !
226+ \brief combine a value into the reducer
227+ */
228+ RAJA_HOST_DEVICE RAJA_INLINE void operator +=(T val)
229+ {
230+ combine (std::move (val));
231+ }
232+
217233private:
218234 BinaryOp m_op;
219235
@@ -241,6 +257,80 @@ struct BinaryTreeReduce
241257 }
242258};
243259
260+ /* !
261+ \brief Reduce class that does a reduction with a left fold.
262+ */
263+ template <typename T>
264+ struct KahanSum
265+ {
266+ static_assert (std::is_floating_point_v<T>, " T must be a floating point type" );
267+
268+ RAJA_HOST_DEVICE RAJA_INLINE constexpr explicit KahanSum (
269+ T init = T()) noexcept
270+ : m_accumulated_value(std::move(init))
271+ , m_accumulated_carry(T())
272+ {}
273+
274+ KahanSum (KahanSum const &) = delete ;
275+ KahanSum& operator =(KahanSum const &) = delete ;
276+ KahanSum (KahanSum&&) = delete ;
277+ KahanSum& operator =(KahanSum&&) = delete ;
278+
279+ ~KahanSum () = default ;
280+
281+ /* !
282+ \brief reset the combined value of the reducer to the identity
283+ */
284+ RAJA_HOST_DEVICE RAJA_INLINE void clear () noexcept
285+ {
286+ m_accumulated_value = T ();
287+ m_accumulated_carry = T ();
288+ }
289+
290+ /* !
291+ \brief return the combined value and clear the reducer
292+ */
293+ RAJA_HOST_DEVICE RAJA_INLINE T get_and_clear ()
294+ {
295+ T accumulated_value = std::move (m_accumulated_value);
296+
297+ clear ();
298+
299+ return accumulated_value;
300+ }
301+
302+ /* !
303+ \brief return the combined value
304+ */
305+ RAJA_HOST_DEVICE RAJA_INLINE T get () { return m_accumulated_value; }
306+
307+ /* !
308+ \brief combine a value into the reducer
309+ */
310+ RAJA_HOST_DEVICE RAJA_INLINE void combine (T val)
311+ {
312+ // volatile used to prevent compiler optimizations that assume
313+ // floating-point operations are associative
314+ T y = val - m_accumulated_carry;
315+ volatile T t = m_accumulated_value + y;
316+ volatile T z = t - m_accumulated_value;
317+ m_accumulated_carry = z - y;
318+ m_accumulated_value = t;
319+ }
320+
321+ /* !
322+ \brief combine a value into the reducer
323+ */
324+ RAJA_HOST_DEVICE RAJA_INLINE void operator +=(T val)
325+ {
326+ combine (std::move (val));
327+ }
328+
329+ private:
330+ T m_accumulated_value;
331+ T m_accumulated_carry;
332+ };
333+
244334template <typename T, typename BinaryOp>
245335using HighAccuracyReduce =
246336 std::conditional_t <RAJA ::operators::is_fp_associative<T>::value,
@@ -291,6 +381,25 @@ binary_tree_reduce(Iter begin, Iter end, T init, BinaryOp op)
291381 return reducer.get_and_clear ();
292382}
293383
384+ /* !
385+ \brief Combine into a single value using a kahan sum using O(N) operations
386+ and O(1) memory
387+ */
388+ template <typename Iter, typename T>
389+ RAJA_HOST_DEVICE RAJA_INLINE T
390+ kahan_sum (Iter begin, Iter end, T init)
391+ {
392+ KahanSum<T> reducer (std::move (init));
393+
394+ for (; begin != end; ++begin)
395+ {
396+
397+ reducer.combine (*begin);
398+ }
399+
400+ return reducer.get_and_clear ();
401+ }
402+
294403/* !
295404 \brief reducer that uses a high accuracy implementation when round-off error
296405 is a concern, or a faster algorithm with it is not a concern
@@ -358,6 +467,25 @@ RAJA_HOST_DEVICE RAJA_INLINE
358467 std::move (op));
359468}
360469
470+ /* !
471+ \brief Accumulate given range to a single value
472+ using a left fold algorithm in O(N) operations and O(1) extra memory
473+ see https://en.cppreference.com/w/cpp/algorithm/accumulate
474+ */
475+ template <typename Container,
476+ typename T = detail::ContainerVal<Container>>
477+ RAJA_HOST_DEVICE RAJA_INLINE
478+ concepts::enable_if_t <T, type_traits::is_range<Container>,
479+ std::is_floating_point<T>>
480+ kahan_sum (Container&& c,
481+ T init = T())
482+ {
483+ using std::begin;
484+ using std::end;
485+
486+ return detail::kahan_sum (begin (c), end (c), std::move (init));
487+ }
488+
361489/* !
362490 \brief Reduce given range to a single value
363491 using an algorithm with high accuracy when floating point round off is a
0 commit comments