Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the average of several chrono::time_points

Tags:

c++

c++14

chrono

The formula for getting the average of several numbers is of course well known:

And this formula can easily be used to get the average of chrono::durations:

template <class Rep0, class Period0>
auto
sum(const std::chrono::duration<Rep0, Period0>& d0)
{
    return d0;
}

template <class Rep0, class Period0, class ...Rep, class ...Period>
auto
sum(const std::chrono::duration<Rep0, Period0>& d0,
    const std::chrono::duration<Rep, Period>& ...d)
{
    return d0 + sum(d...);
}

template <class ...Rep, class ...Period>
auto
avg(const std::chrono::duration<Rep, Period>& ...d)
{
    return sum(d...) / static_cast<std::common_type_t<Rep...>>(sizeof...(d));
}

But chrono::time_points can't be added to one another. How can I average time_points?

like image 329
Howard Hinnant Avatar asked Jan 11 '18 17:01

Howard Hinnant


1 Answers

It helps to start out with the assumption that you can add time_points, and then manipulate the formula to eliminate those additions:

First separate out t1 from the sum:

Next both add and subtract t1:

Factor and rearrange:

And then, since you are subtracting t1 the same number of times as you are summing, you can include that into the sum:

Now you are summing durations instead of time_points! As we already have a function to sum durations, averaging time_points can easily build on that:

template <class Clock, class Duration0, class ...Duration>
auto
avg(const std::chrono::time_point<Clock, Duration0>& t0,
    const std::chrono::time_point<Clock, Duration>& ...t)
{
    constexpr auto N =
        static_cast<std::common_type_t<typename Duration0::rep,
                                       typename Duration::rep...>>(1 + sizeof...(t));
    return t0 + sum((t - t0)...) / N;
}

Averaging a single time_point is a special case since sum of durations does not handle summing zero durations (what would be the units?). So an overload for that case is easily added:

template <class Clock, class Duration0>
auto
avg(const std::chrono::time_point<Clock, Duration0>& t0)
{
    return t0;
}

This is written in C++14. It can be coded in C++11, using the trailing return type declaration syntax, which is more verbose, but completely doable.

like image 152
Howard Hinnant Avatar answered Oct 07 '22 18:10

Howard Hinnant