{"id":1432,"date":"2016-10-24T08:55:27","date_gmt":"2016-10-24T15:55:27","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=1432"},"modified":"2016-10-24T09:27:54","modified_gmt":"2016-10-24T16:27:54","slug":"chrono-random","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=1432","title":{"rendered":"CHRONO + RANDOM = ?"},"content":{"rendered":"<p>Being a quick sketch combining <code>&lt;chrono&gt;<\/code> and <code>&lt;random&gt;<\/code> functionality, with cryptarithmetic interludes&#8230;<\/p>\n<p>At CppCon this year there were several good talks about randomness and time calculations in C++. On randomness: Walter Brown&#8217;s <a href=\"https:\/\/www.youtube.com\/watch?v=6DPkyvkMkk8\">What C++ Programmers Need to Know About Header &lt;random&gt;<\/a> and Cheinan Marks&#8217; <a href=\"https:\/\/www.youtube.com\/watch?v=4_QO1nm7uJs\">I Just Wanted a Random Integer!<\/a> were both excellent talks. And Howard Hinnant gave several great talks: <a href=\"https:\/\/www.youtube.com\/watch?v=P32hvk8b13M\">A &lt;chrono&gt; Tutorial<\/a>, and <a href=\"https:\/\/www.youtube.com\/watch?v=Vwd3pduVGKY\">Welcome to the Time Zone<\/a>, a followup to his talk from last year, <a href=\"https:\/\/www.youtube.com\/watch?v=tzyGjOm8AKo\">A C++ Approach to Dates and Times<\/a>.<\/p>\n<p><strong>CHRONO + RANDOM = HORRID ?<\/strong><\/p>\n<p>That&#8217;s perhaps a little unfair, but recently I ran into the need to compute a random period of time. I think this is a common use case for things like backoff schemes for network retransmission. And it seemed to me that the interaction of <code>&lt;chrono&gt;<\/code> and <code>&lt;random&gt;<\/code> was not quite as good as it could be:<\/p>\n<pre lang=\"cpp\">\r\nsystem_clock::duration minTime = 0s;\r\nsystem_clock::duration maxTime = 5s;\r\nuniform_int_distribution<> d(minTime.count(), maxTime.count());\r\n\/\/ 'gen' here is a Mersenne twister engine\r\nauto nextTransmissionWindow = system_clock::duration(d(gen));\r\n<\/pre>\n<p>This code gets more complex when you start computing an exponential backoff. Relatively straightforward, but clumsy, especially if you want a floating-point base for your exponent calculation: <code>system_clock::duration<\/code> has an integral representation, so in all likelihood you end up having to cast multiple times, using either <code>static_cast<\/code> or <code>duration_cast<\/code>. That&#8217;s a bit messy.<\/p>\n<p>I remembered some code from another talk: Andy Bond&#8217;s <a href=\"https:\/\/www.youtube.com\/watch?v=ZCGyvPDM0YY\">AAAARGH!? Adopting Almost Always Auto Reinforces Good Habits!?<\/a> in which he presented a function to make a uniform distribution by inferring its argument type, useful in generic code. Something like the following:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename A, typename B = A,\r\n          typename C = std::common_type_t<A, B>,\r\n          typename D = std::uniform_int_distribution<C>>\r\ninline auto make_uniform_distribution(const A& a,\r\n                                      const B& b = std::numeric_limits<B>::max())\r\n  -> std::enable_if_t<std::is_integral<C>::value, D>\r\n{\r\n  return D(a, b);\r\n}\r\n<\/pre>\n<p>Of course, the standard also provides <code>uniform_real_distribution<\/code>, so we can provide another template and overload the function for real numbers:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename A, typename B = A,\r\n          typename C = std::common_type_t<A, B>,\r\n          typename D = std::uniform_real_distribution<C>>\r\ninline auto make_uniform_distribution(const A& a,\r\n                                      const B& b = B{1})\r\n  -> std::enable_if_t<std::is_floating_point<C>::value, D>\r\n{\r\n  return D(a, b);\r\n}\r\n<\/pre>\n<p>And with these two in hand, it&#8217;s easy to write a <code>uniform_duration_distribution<\/code> that uses the correct distribution for its underlying representation (using a home-made type trait to constrain it to <code>duration<\/code> types).<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct is_duration : std::false_type {};\r\ntemplate <typename Rep, typename Period>\r\nstruct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};\r\n\r\ntemplate <typename Duration = std::chrono::system_clock::duration,\r\n          typename = std::enable_if_t<is_duration<Duration>::value>>\r\nclass uniform_duration_distribution\r\n{\r\npublic:\r\n  using result_type = Duration;\r\n\r\n  explicit uniform_duration_distribution(\r\n      const Duration& a = Duration::zero(),\r\n      const Duration& b = Duration::max())\r\n    : m_a(a), m_b(b)\r\n  {}\r\n\r\n  void reset() {}\r\n\r\n  template <typename Generator>\r\n  result_type operator()(Generator& g)\r\n  {\r\n    auto d = make_uniform_distribution(m_a.count(), m_b.count());\r\n    return result_type(d(g));\r\n  }\r\n\r\n  result_type a() const { return m_a; }\r\n  result_type b() const { return m_b; }\r\n  result_type min() const { return m_a; }\r\n  result_type max() const { return m_b; }\r\n\r\nprivate:\r\n  result_type m_a;\r\n  result_type m_b;\r\n};\r\n<\/pre>\n<p>Having written this, we can once again overload <code>make_uniform_distribution<\/code> to provide for <code>duration<\/code> types:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename A, typename B = A,\r\n          typename C = std::common_type_t<A, B>,\r\n          typename D = uniform_duration_distribution<C>>\r\ninline auto make_uniform_distribution(const A& a,\r\n                                      const B& b = B::max()) -> D\r\n{\r\n  return D(a, b);\r\n}\r\n<\/pre>\n<p>And now we can compute a random <code>duration<\/code> more expressively and tersely, and, I think, in the spirit of the existing functionality that exists in <code>&lt;chrono&gt;<\/code> for manipulating <code>duration<\/code>s.<\/p>\n<pre lang=\"cpp\">\r\nauto d = make_uniform_distribution(0s, 5000ms);\r\nauto nextTransmissionWindow = d(gen);\r\n<\/pre>\n<p><strong>CHRONO + RANDOM = DREAMY<\/strong><\/p>\n<p>I leave it as an exercise for the reader to solve these cryptarithmetic puzzles. As for the casting problems, for now, I&#8217;m living with them.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Being a quick sketch combining &lt;chrono&gt; and &lt;random&gt; functionality, with cryptarithmetic interludes&#8230; At CppCon this year there were several good talks about randomness and time calculations in C++. On randomness: Walter Brown&#8217;s What C++ Programmers Need to Know About Header &lt;random&gt; and Cheinan Marks&#8217; I Just Wanted a Random Integer!&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-1432","post","type-post","status-publish","format-standard","hentry","category-cpp"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1432","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1432"}],"version-history":[{"count":6,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1432\/revisions"}],"predecessor-version":[{"id":1438,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1432\/revisions\/1438"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1432"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1432"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1432"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}