Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dividing and multiplying std::chrono::durations

Tags:

c++

c++11

chrono

I'm calculating some changes in time over time using std::chrono::duration in order to obtain a approximation of a derative and trapezoid integral.

I would like to perform some common operations on a duration, but unfortunately failing to do so, probably because I do not understand chrono properly.

using std::chrono::milliseconds;
using namespace std;

milliseconds eightms = milliseconds(8);
milliseconds fourms = milliseconds(4);
milliseconds twoms = milliseconds(eightms / fourms); //<-- why do I need this cast?
milliseconds twoms = eightms / fourms;

cout << "twoms = " << twoms.count() << " ms" << endl;

expected output would be

twoms = 2 ms

If I do not use the cast above I get this for me cryptic compiler error, It works as expected when I cast the result of the division to milliseconds again.

dur_div_mult.cpp: In function ‘int main()’:
dur_div_mult.cpp:13:11: error: no match for ‘operator=’ (operand types are ‘std::chrono::milliseconds {aka std::chrono::duration<long int, std::ratio<1l, 1000l> >}’ and ‘std::__success_type<long int>::type {aka long int}’)
     twoms = eightms/fourms;
           ^
In file included from dur_div_mult.cpp:2:0:
/usr/include/c++/5/chrono:274:12: note: candidate: std::chrono::duration<_Rep, _Period>& std::chrono::duration<_Rep, _Period>::operator=(const std::chrono::duration<_Rep, _Period>&) [with _Rep = long int; _Period = std::ratio<1l, 1000l>]
  duration& operator=(const duration&) = default;
        ^

/usr/include/c++/5/chrono:274:12: note: no known conversion for argument 1 from ‘std::__success_type::type {aka long int}’ to ‘const std::chrono::duration >&’

Also multiplying 2ms * 4ms with results doesn't work as I would expect.

twoms = milliseconds(2);
fourms = milliseconds(4);
eightms = twoms * fourms;
cout << "eightms = " << eightms.count() << " ms" << endl;

expected output would be:

eightms = 8 ms

dur_div_mult.cpp: In function ‘int main()’:
dur_div_mult.cpp:18:21: error: no match for ‘operator*’ (operand types are ‘std::chrono::milliseconds {aka std::chrono::duration<long int, std::ratio<1l, 1000l> >}’ and ‘std::chrono::milliseconds {aka std::chrono::duration<long int, std::ratio<1l, 1000l> >}’)
     eightms = twoms * fourms;
                     ^
In file included from dur_div_mult.cpp:2:0:
/usr/include/c++/5/chrono:424:7: note: candidate: template<class _Rep1, class _Rep2, class _Period> constexpr std::chrono::duration<typename std::chrono::__common_rep_type<_Rep2, _Rep1>::type, _Period> std::chrono::operator*(const _Rep1&, const std::chrono::duration<_Rep, _Period>&)
       operator*(const _Rep1& __s, const duration<_Rep2, _Period>& __d)
       ^
/usr/include/c++/5/chrono:424:7: note:   template argument deduction/substitution failed:
/usr/include/c++/5/chrono: In substitution of ‘template<class _Rep1, class _Rep2, class _Period> constexpr std::chrono::duration<typename std::chrono::__common_rep_type<_Rep2, _Rep1>::type, _Period> std::chrono::operator*(const _Rep1&, const std::chrono::duration<_Rep, _Period>&) [with _Rep1 = std::chrono::duration<long int, std::ratio<1l, 1000l> >; _Rep2 = long int; _Period = std::ratio<1l, 1000l>]’:
dur_div_mult.cpp:18:23:   required from here
/usr/include/c++/5/chrono:424:7: error: no type named ‘type’ in ‘struct std::common_type<long int, std::chrono::duration<long int, std::ratio<1l, 1000l> > >’
/usr/include/c++/5/chrono:414:7: note: candidate: template<class _Rep1, class _Period, class _Rep2> constexpr std::chrono::duration<typename std::chrono::__common_rep_type<_Rep1, _Rep2>::type, _Period> std::chrono::operator*(const std::chrono::duration<_Rep1, _Period1>&, const _Rep2&)
       operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s)
       ^
/usr/include/c++/5/chrono:414:7: note:   template argument deduction/substitution failed:
/usr/include/c++/5/chrono: In substitution of ‘template<class _Rep1, class _Period, class _Rep2> constexpr std::chrono::duration<typename std::chrono::__common_rep_type<_Rep1, _Rep2>::type, _Period> std::chrono::operator*(const std::chrono::duration<_Rep1, _Period1>&, const _Rep2&) [with _Rep1 = long int; _Period = std::ratio<1l, 1000l>; _Rep2 = std::chrono::duration<long int, std::ratio<1l, 1000l> >]’:
dur_div_mult.cpp:18:23:   required from here
/usr/include/c++/5/chrono:414:7: error: no type named ‘type’ in ‘struct std::common_type<long int, std::chrono::duration<long int, std::ratio<1l, 1000l> > >’

Clearly I'm not using the std::chrono::duration correctly, but what am I doing wrong?

like image 421
hetepeperfan Avatar asked Aug 02 '19 13:08

hetepeperfan


1 Answers

<chrono> follows a strict subset of dimensional analysis rules.

A duration has a unit of time. Let's ignore the precision of the units of time briefly and just refer to it generally as T.

A scalar, (int, double, etc.), has no unit at all.

If you multiply two durations together this would give you T2 units (but this won't compile, keep reading). If you divide two durations, you get a scalar: T0. If you multiply a duration by a scalar, you get T1 (just time). If you divide a duration by a scalar, you also get T1 (just time). And if you divide a scalar by a duration, you get T-1, which is often referred to as a frequency (but this won't compile either).

<chrono> provides that subset of physics where the result can be expressed either as T1 (a duration) or T0 (a scalar). Other exponents are not allowed and result in compile-time errors. This isn't because they are wrong, but just outside the scope of this library.

eightms / fourms results in the scalar 2.

What you intend is:

milliseconds twoms = eightms / 4;
like image 158
Howard Hinnant Avatar answered Oct 29 '22 23:10

Howard Hinnant