6

For example:

for (...)
{
    ... std::uniform_real_distribution<float>(min, max)(rng) ...
}

Intuitively it seems to me that the constructor can't need to do much besides store the two values, and there shouldn't be any state in the uniform_*_distribution instance. I haven't profiled it myself (I'm not at that kind of stage in the project yet), but I felt this question belonged out there :)

I am aware that this would be a bad idea for some distribution types - for example, std::normal_distribution might generate its numbers in pairs, and the second number would be wasted each time.

I feel what I have is more readable than just accessing rng() and doing the maths myself, but I'd be interested if there are any other ways to write this more straightforwardly.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
entheh
  • 938
  • 1
  • 9
  • 17
  • Distributions can have internal state, so you may want to keep the distribution around if you're going to use it repeatedly. – Kerrek SB Jan 21 '16 at 21:20
  • Wouldn't the efficiency of this approach depend very much on how much other work is happening in that loop? It could also be platform dependent, so the easiest way to find out would appear to be to code up your use case and profile it on the relevant platform(s). – njuffa Jan 21 '16 at 21:20
  • 2
    "*I feel what I have is more readable than just accessing `rng()` and doing the maths myself*" Well, that won't be more readable than creating the distribution outside of the loop and accessing inside of it. So I see no reason why you should *want* to create it inside of the loop, no matter how efficient it is. – Nicol Bolas Jan 21 '16 at 21:20
  • 2
    Why do you fell you need to create the distribution in each loop? – NathanOliver Jan 21 '16 at 21:22
  • 1
    @NathanOliver perhaps min and max are changing every iteration? – T.C. Jan 21 '16 at 21:26
  • 4
    No `uniform_real_distribution` implementation I know of has any special state. OTOH, `uniform_real_distribution` [is a bad idea](http://stackoverflow.com/questions/25668600/is-1-0-a-valid-output-from-stdgenerate-canonical). – T.C. Jan 21 '16 at 21:28
  • @T.C. Good to know it'll round wrongly. Luckily my algorithm isn't sensitive to this. – entheh Jan 21 '16 at 21:39
  • @NicolBolas Brevity, to-the-point-ness and speed-coding. Typing it inline is easier (no cursor gymnastics) than dedicating an extra line to it and choosing a name for it, and it keeps the reader focused on what I'm actually doing. I can easily accept that this is personal preference of course. – entheh Jan 21 '16 at 21:39

2 Answers2

6

std::uniform_real_distribution's objects are lightweight, so it's not a problem to construct them each time inside the loop.

Sometimes, the hidden internal state of distribution is important, but not in this case. reset() function is doing nothing in all popular STL implementations:

void
reset() { }

For example, it's not true for std::normal_distribution:

void
reset()
{ _M_saved_available = false; }
SashaMN
  • 708
  • 5
  • 16
0

Well, some rng's have substantial state, e.g. Mersenne twister has something like 600 words of state (although I don't know about the C++ implementation of that). So there's the potential for taking up some time in the loop just to repeatedly create the rng.

However, it may well be that even when taking the state into account, it's still fast enough that taking the extra time to construct the rng doesn't matter. Only profiling can tell you for sure.

My personal preference is to move the rng out of the loop and compute the desired value via a simple formula if possible (e.g. min + (max - min)*x for a uniform distribution or mu + sigma*x for a Gaussian distribution).

Robert Dodier
  • 16,905
  • 2
  • 31
  • 48
  • 3
    Don't worry, the generator is global in my case. It's only the distribution object (which does the work of your simple formulae) that I'm making as a temporary. Although you answered the wrong question, it's a good answer; and of course, in addition to what you raised, making the generator temporary every time could, depending on the generator, result in [Dilbert](http://dilbert.com/strip/2001-10-25)/[xkcd](https://xkcd.com/221/)-style random numbers ;) – entheh Jan 22 '16 at 12:50