2010-10-30

`<chrono>`

Utilities
A few simple utility functions for working with `duration`

s.

// round down template <class To, class Rep, class Period> To floor(const std::chrono::duration<Rep, Period>& d) { To t = std::chrono::duration_cast<To>(d); if (t > d) --t; return t; } // round to nearest, to even on tie template <class To, class Rep, class Period> To round(const std::chrono::duration<Rep, Period>& d) { To t0 = std::chrono::duration_cast<To>(d); To t1 = t0; ++t1; auto diff0 = d - t0; auto diff1 = t1 - d; if (diff0 == diff1) { if (t0.count() & 1) return t1; return t0; } else if (diff0 < diff1) return t0; return t1; } // round up template <class To, class Rep, class Period> To ceil(const std::chrono::duration<Rep, Period>& d) { To t = std::chrono::duration_cast<To>(d); if (t < d) ++t; return t; }

The beauty of the chrono library is the ease and accuracy with which such
conversions can be made. For example to convert from milliseconds (1/1000 of
a second), to 1/30 of a second, one must multiply the milliseconds by 0.03.
It is common knowledge that you can't exactly represent 0.03 in a computer.
Nevertheless `round` will exactly (with no round off error) detect a tie
and round to even when this happens. The differences `diff0` and
`diff1` are not approximate, but exact differences, even when `d`
has the units of millisecond and `To` is 1/30 of a second. The unit of
`diff0` and `diff1` is 1/3000 of a second which both millisecond
and 1/30 of a second exactly convert to (with no truncation error).

Similarly, the comparison `t < d` in `ceil` is exact, even when
there is no exact conversion between `t` and `d`.

#include <iostream> #include <chrono_io> int main() { using namespace std::chrono; milliseconds ms(2500); std::cout << floor<seconds>(ms) << '\n'; std::cout << round<seconds>(ms) << '\n'; std::cout << ceil<seconds>(ms) << '\n'; ms = milliseconds(2516); typedef duration<long, std::ratio<1, 30>> frame_rate; std::cout << floor<frame_rate>(ms) << '\n'; std::cout << round<frame_rate>(ms) << '\n'; std::cout << ceil<frame_rate>(ms) << '\n'; } 2 seconds 2 seconds 3 seconds 75 [1/30]seconds 75 [1/30]seconds 76 [1/30]seconds

An interesting exercise is to find out how many frames go by (at 1/30 second
frame rate) in 2516 milliseconds using `xtime` from C1x (without using
the chrono library! :-)).

`abs`

template <class Rep, class Period, class = typename std::enable_if < std::chrono::duration<Rep, Period>::min() < std::chrono::duration<Rep, Period>::zero() >::type > constexpr inline std::chrono::duration<Rep, Period> abs(std::chrono::duration<Rep, Period> d) { return d >= d.zero() ? d : -d; }

Note that `abs`

is disabled for unsigned durations. My reasoning is
that if you try to call `abs`

with an unsigned duration, the chances
are high that there is a logical mistake in your code, and so a compile-time
diagnostic is better, than a silent identity function.