1

I would like to use the distributions provided in <random> to compute an inverse CDF calculation. I see that normal distribution has the following method

template<class Generator>
result_type std::normal_distribution<RealType>::operator()(Generator& g);

where

g - an uniform random bit generator object

My idea was to make a custom generator that simply passed a single value (the probability that I would like to look up the inverse x value for).

class ConstantGenerator
{
public:
    ConstantGenerator(double value) : m_value(value) {}
    double min() const { return 0.0; }
    double max() const { return 1.0; }
    double operator()(){ return m_value; }
    using result_type = double;
private:
    double m_value = 0.0;
};

Example usage would be

int main()
{
    std::normal_distribution<double> dist{10.0, 1.0};
    ConstantGenerator gen{0.5};
    std::cout << dist(gen);
}

In this example, I created a normal distribution with Mean=10, StdDev=1 therefore I was hoping that my dist(gen) call with passing p=0.5 would return 10 (the mean) but instead it returns 1.46885.

How can I modify my ConstantGenerator to use the existing C++11 distributions to perform inverse CDF calculations? Or am I incorrect in my assumption that operator() performs an inverse CDF in the first place?

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • For other dummies than me: CDF -> [Cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) ;-) – Scheff's Cat Jul 17 '20 at 14:22
  • Generators in C++ are source of random BITS. There are no floats, doubles etc in generators, just bits typically packed into unsigned words – Severin Pappadeux Jul 17 '20 at 16:34
  • You might be thinking about distributions, what you put out looks like Dirac delta function distribution with PDF(x)=δ(x-0.5) – Severin Pappadeux Jul 17 '20 at 16:48
  • I probably misunderstood your question, but if you want to calculate the CDF of a [normal distribution](https://en.wikipedia.org/wiki/Normal_distribution) you may need [std::erf](https://en.cppreference.com/w/cpp/numeric/math/erf) instead. – Bob__ Jul 17 '20 at 18:28
  • 1
    Possibly related [question](https://stackoverflow.com/questions/60472139/computing-the-inverse-of-the-complementary-error-function-erfcinv-in-c), the answer to which includes a single-precision implementation of the inverse of the CDF of the standard normal distribution, a function called `my_normcdfinvf()`. – njuffa Jul 17 '20 at 18:49
  • I was using the normal distribution as an example, but I was hoping to leverage any of the distributions available in the `` header (normal, weibull, gamma, etc) – Cory Kramer Jul 17 '20 at 19:12

1 Answers1

1

std::normal_distribution is not a normal distribution function. Instead, it is a function that takes in random bits (like Severin Pappdeux already mentioned), and outputs values that are normally distributed. There is nothing in the standard that defines how the input bits are used.

A possible implementation of std::normal_distribution that I can think of is as follows: when you want a normally distributed value, it calls the random bit generator multiple times, assumes the output of that generator is distributed uniformly, then maps those outputs to the desired range of floating point values, and then just averages those values. You can see that this would not work as intended if you give it a generator that always gives the same value.

Another issue with your ConstantGenerator is that it doesn't follow the requirements for UniformRandomBitGenerator; in particular, the output should be an unsigned integer.

You can try to implement the inverse CDF of the normal distribution yourself.

G. Sliepen
  • 7,637
  • 1
  • 15
  • 31