Skip to main content
Added some example material and a live demo.
Source Link
Stefan
  • 813
  • 1
  • 7
  • 18

Usage example:

std::array<volatile float, 5> arr1 { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };
volatile float arr2[] { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };

volatile float res1 = sum(arr1);
volatile float res2 = avg(arr2, sizeof(arr2)/sizeof(arr2[0]));
volatile auto res3 = avg(1.2f, 1.4f, 1.6);

Live demo at: https://godbolt.org/g/DMHv7Y

The sum functions:

The sum functions:

Usage example:

std::array<volatile float, 5> arr1 { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };
volatile float arr2[] { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f };

volatile float res1 = sum(arr1);
volatile float res2 = avg(arr2, sizeof(arr2)/sizeof(arr2[0]));
volatile auto res3 = avg(1.2f, 1.4f, 1.6);

Live demo at: https://godbolt.org/g/DMHv7Y

The sum functions:

Source Link
Stefan
  • 813
  • 1
  • 7
  • 18

C++ sum and averaging functions for arrays and argument sets

Here are two sets of variadic C++ functions to do fast summing and averaging of arrays (plain & std::array) or argument sets, (re)written as part of my generic toolbox.

The sum functions are pretty generic, the averaging ones operate on floating point based types only (the integer counterparts are application specific).

The sum functions:

#include <cstdint>
#include <utility>
#include <type_traits>
#include <array>

/**
 * Return the sum of all values in the provided `std::array`.
 * @param  arr std::array
 * @return     sum
 */
template <typename T, size_t S>
inline constexpr auto sum(const std::array<T, S> arr) {
    std::remove_cv_t<std::remove_reference_t<T>> t = 0;
    for (const auto v : arr) {
        t += v;
    }
    return t;
}

/**
 * Return the sum of all values in the provided plain array.
 * @param  arr Array
 * @param  l   length
 * @return     sum
 */
template <typename T, typename = typename std::enable_if<std::is_pointer<T>::value, void>::type>
inline constexpr auto sum(const T arr, size_t l) {
    std::remove_cv_t<
        std::remove_reference_t<
            decltype(arr[0])>> t = 0;
    for (size_t i = 0; i < l; i++) {
        t += arr[i];
    }
    return t;
}

/**
 * Return the sum of all values. Tries to use the common type for the return value.
 * @param  ts Arguments to sum
 * @return    sum
 */
template <typename... Ts,
          typename = typename std::enable_if<!std::is_pointer<std::common_type_t<Ts...>>::value, void>::type>
inline constexpr auto sum(Ts&&... ts) {
    std::common_type_t<Ts...> t = 0;
    for (const auto val : std::initializer_list<std::common_type_t<Ts...>>{ts...}) {
        t += val;
    }
    return t;
}

The averaging functions:

#include <cstdint>
#include <utility>
#include <type_traits>
#include <array>

/**
 * Return the average of all values in the provided `std::array`.
 * @param  arr std::array
 * @return     average
 */
template <typename T, size_t S, typename = typename std::enable_if<std::is_floating_point<T>::value, void>::type>
inline constexpr auto avg(const std::array<T, S> arr) {
    std::remove_cv_t<std::remove_reference_t<T>> t = 0;
    for (const auto v : arr) {
        t += v;
    }
    return t / S;
}

/**
 * Return the average of all values in the provided array.
 * @param  arr array
 * @param  l   length
 * @return     average
 */
template <typename T, typename = typename std::enable_if<std::is_pointer<T>::value && std::is_floating_point<std::remove_pointer_t<T>>::value, void>::type>
inline constexpr auto avg(const T arr, size_t l) {
    std::remove_cv_t<
        std::remove_reference_t<
            decltype(arr[0])>> t = 0;
    for (size_t i = 0; i < l; i++) {
        t += arr[i];
    }
    return t / l;
}

/**
 * Return the average of all arguments. Tries to use the common type for the return value.
 * @param  ts Arguments to sum
 * @return    average
 */
template <typename... Ts,
          typename = typename std::enable_if<!std::is_pointer<std::common_type_t<Ts...>>::value && std::is_floating_point<std::common_type_t<Ts...>>::value, void>::type>
inline constexpr auto avg(Ts&&... ts) {
    std::common_type_t<Ts...> t = 0;
    for (const auto val : std::initializer_list<std::common_type_t<Ts...>>{ts...}) {
        t += val;
    }
    return t / sizeof...(Ts);
}

The generic patterns here can of course be used to create all kinds of data processing tools. I'd love to know if/how I can improve them.