Skip to content
Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

CHRONO + RANDOM = ?

elbeno, 24 October, 201624 October, 2016

Being a quick sketch combining <chrono> and <random> functionality, with cryptarithmetic interludes…

At CppCon this year there were several good talks about randomness and time calculations in C++. On randomness: Walter Brown’s What C++ Programmers Need to Know About Header <random> and Cheinan Marks’ I Just Wanted a Random Integer! were both excellent talks. And Howard Hinnant gave several great talks: A <chrono> Tutorial, and Welcome to the Time Zone, a followup to his talk from last year, A C++ Approach to Dates and Times.

CHRONO + RANDOM = HORRID ?

That’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 <chrono> and <random> was not quite as good as it could be:

system_clock::duration minTime = 0s;
system_clock::duration maxTime = 5s;
uniform_int_distribution<> d(minTime.count(), maxTime.count());
// 'gen' here is a Mersenne twister engine
auto nextTransmissionWindow = system_clock::duration(d(gen));

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: system_clock::duration has an integral representation, so in all likelihood you end up having to cast multiple times, using either static_cast or duration_cast. That’s a bit messy.

I remembered some code from another talk: Andy Bond’s AAAARGH!? Adopting Almost Always Auto Reinforces Good Habits!? in which he presented a function to make a uniform distribution by inferring its argument type, useful in generic code. Something like the following:

template ,
          typename D = std::uniform_int_distribution>
inline auto make_uniform_distribution(const A& a,
                                      const B& b = std::numeric_limits::max())
  -> std::enable_if_t::value, D>
{
  return D(a, b);
}

Of course, the standard also provides uniform_real_distribution, so we can provide another template and overload the function for real numbers:

template ,
          typename D = std::uniform_real_distribution>
inline auto make_uniform_distribution(const A& a,
                                      const B& b = B{1})
  -> std::enable_if_t::value, D>
{
  return D(a, b);
}

And with these two in hand, it’s easy to write a uniform_duration_distribution that uses the correct distribution for its underlying representation (using a home-made type trait to constrain it to duration types).

template 
struct is_duration : std::false_type {};
template 
struct is_duration> : std::true_type {};

template ::value>>
class uniform_duration_distribution
{
public:
  using result_type = Duration;

  explicit uniform_duration_distribution(
      const Duration& a = Duration::zero(),
      const Duration& b = Duration::max())
    : m_a(a), m_b(b)
  {}

  void reset() {}

  template 
  result_type operator()(Generator& g)
  {
    auto d = make_uniform_distribution(m_a.count(), m_b.count());
    return result_type(d(g));
  }

  result_type a() const { return m_a; }
  result_type b() const { return m_b; }
  result_type min() const { return m_a; }
  result_type max() const { return m_b; }

private:
  result_type m_a;
  result_type m_b;
};

Having written this, we can once again overload make_uniform_distribution to provide for duration types:

template ,
          typename D = uniform_duration_distribution>
inline auto make_uniform_distribution(const A& a,
                                      const B& b = B::max()) -> D
{
  return D(a, b);
}

And now we can compute a random duration more expressively and tersely, and, I think, in the spirit of the existing functionality that exists in <chrono> for manipulating durations.

auto d = make_uniform_distribution(0s, 5000ms);
auto nextTransmissionWindow = d(gen);

CHRONO + RANDOM = DREAMY

I leave it as an exercise for the reader to solve these cryptarithmetic puzzles. As for the casting problems, for now, I’m living with them.

C++

Post navigation

Previous post
Next post

Related Posts

C++ Reflection: Another Monad

4 March, 20264 March, 2026

“Discovery consists of seeing what everybody has seen, and thinking what nobody has thought.” — Albert Szent-Györgi, 1937 Nobel Laureate for Medicine I’m sure others have thought this, but they’re certainly not saying much about it. Barry’s recent blog post “Behold the power of meta::substitute” got so close to saying…

Read More

Familiar Template Syntax IILEs

23 October, 20196 May, 2024

A lot has already been said in the blogosphere about the use of immediately-invoked lambda expressions (IILEs) for initialization, and they’re certainly very useful. In C++20, P0428 gives us “familiar template syntax” for lambdas. Now, instead of writing a regular generic lambda: we have the option to use “familiar template…

Read More

Exercising Ranges (part 4)

1 July, 20151 July, 2015

(Start at the beginning of the series if you want more context.) On reversibility It occurs to me that I’ve been touting reversibility as a good thing, both implicitly and explicitly (for polynomials), and the reason for that is not just that I might want to print polynomials in natural…

Read More

Comment

  1. Ilya says:
    22 December, 2016 at 4:42 am

    check out my project: https://github.com/effolkronium/TinyRandom

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

©2026 Why is a raven like a writing desk? | WordPress Theme by SuperbThemes