2

When I look at the documentation for std::exponential_distribution, it does not seem to expose a standard way for changing the lambda parameter at runtime.

There is a param method, but it takes the opaque member type param_type, and the only documented way of obtaining an object of this type is to call param with no arguments, but that would imply a different instance must have first been created with that parameter.

Below, I show two non-documented ways of resetting lambda that compile, but I do not know whether they will result in correct behavior at runtime.

#include <random>
#include <new>

int main(){
    std::random_device rd;
    std::mt19937 gen(rd());
    std::exponential_distribution<double> intervalGenerator(5);

    // How do we change lambda after creation?
    // Construct a param_type using an undocumented constructor?
    intervalGenerator.param(std::exponential_distribution<double>::param_type(7));

    // Destroy and recreate the distribution?
    intervalGenerator.~exponential_distribution();
    new (&intervalGenerator) std::exponential_distribution<double>(9);
}

Is there a documented way to do this, and if not, are either of the two solutions safe to use?

merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • 4
    It's not undocumented. `param_type` can always be constructed using the same parameters as the parent distribution. – Praetorian Apr 03 '17 at 22:27
  • @Praetorian, Is there documentation on its constructor? I could not find any. – merlin2011 Apr 03 '17 at 22:28
  • 3
    The fact that `param_type` can be constructed using the same parameters as its distribution is one of the requirements of the `RandomNumberDistribution` concept (26.5.1.6/9). –  Apr 03 '17 at 22:29

1 Answers1

5

Just assign a new generator to the old instance:

std::exponential_distribution<double> intervalGenerator(5);
intervalGenerator = std::exponential_distribution<double>(7);

Portable, easy to read and obviously correct.


Also,

intervalGenerator.param(std::exponential_distribution<double>::param_type(7));

is safe as described in 26.5.1.6/9 in both N3337 and N4141, so you can use that too. But with the first variant, no portability questions arise to begin with.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • I'm trying to minimize overheads for this change, and I'm concerned about paying for an additional object. It seems silly one must throw away the object and create a whole new object just to reset a parameter. – merlin2011 Apr 03 '17 at 22:23
  • 1
    @merlin2011 There will be no overhead. Stop wasting your time guessing about performance, optimize after actually finding a problem. – Baum mit Augen Apr 03 '17 at 22:25
  • 1
    @Fanael, Fair point. Perhaps I overthought this. :P Will accept when timer expires. – merlin2011 Apr 03 '17 at 22:26
  • @Fanael Also works even at `-O1`. It's an easy optimization for the compiler – Justin Apr 03 '17 at 22:26
  • 1
    @Justin: works even at `-Og`. I just use `-O3` as the default. –  Apr 03 '17 at 22:27
  • On Clang, it seems to need `-O2`, though – Justin Apr 03 '17 at 22:28