简体   繁体   中英

Random Number Generator with Beta Distribution

I need the c or c++ source code of a function like betarand(a,b) that produces random number with beta distribution . I know that I can use boost library but I'm going to port it for CUDA architecture so I need the code. Can somebody help me?
Meantime I have betapdf (Beta Probability density function). But I don't know how to use it for creating random numbers :).

The C++11 random number library doesn't provide a beta distribution. However, a beta distribution can be modelled in terms of two gamma distributions, which the library does provide. I've implemented a beta_distribution in terms of std::gamma_distribution for you. As far as I can tell, it fully conforms with the requirements for a Random Number Distribution.

#include <iostream>
#include <sstream>
#include <string>
#include <random>

namespace sftrabbit {

  template <typename RealType = double>
  class beta_distribution
  {
    public:
      typedef RealType result_type;

      class param_type
      {
        public:
          typedef beta_distribution distribution_type;

          explicit param_type(RealType a = 2.0, RealType b = 2.0)
            : a_param(a), b_param(b) { }

          RealType a() const { return a_param; }
          RealType b() const { return b_param; }

          bool operator==(const param_type& other) const
          {
            return (a_param == other.a_param &&
                    b_param == other.b_param);
          }

          bool operator!=(const param_type& other) const
          {
            return !(*this == other);
          }

        private:
          RealType a_param, b_param;
      };

      explicit beta_distribution(RealType a = 2.0, RealType b = 2.0)
        : a_gamma(a), b_gamma(b) { }
      explicit beta_distribution(const param_type& param)
        : a_gamma(param.a()), b_gamma(param.b()) { }

      void reset() { }

      param_type param() const
      {
        return param_type(a(), b());
      }

      void param(const param_type& param)
      {
        a_gamma = gamma_dist_type(param.a());
        b_gamma = gamma_dist_type(param.b());
      }

      template <typename URNG>
      result_type operator()(URNG& engine)
      {
        return generate(engine, a_gamma, b_gamma);
      }

      template <typename URNG>
      result_type operator()(URNG& engine, const param_type& param)
      {
        gamma_dist_type a_param_gamma(param.a()),
                        b_param_gamma(param.b());
        return generate(engine, a_param_gamma, b_param_gamma); 
      }

      result_type min() const { return 0.0; }
      result_type max() const { return 1.0; }

      result_type a() const { return a_gamma.alpha(); }
      result_type b() const { return b_gamma.alpha(); }

      bool operator==(const beta_distribution<result_type>& other) const
      {
        return (param() == other.param() &&
                a_gamma == other.a_gamma &&
                b_gamma == other.b_gamma);
      }

      bool operator!=(const beta_distribution<result_type>& other) const
      {
        return !(*this == other);
      }

    private:
      typedef std::gamma_distribution<result_type> gamma_dist_type;

      gamma_dist_type a_gamma, b_gamma;

      template <typename URNG>
      result_type generate(URNG& engine,
        gamma_dist_type& x_gamma,
        gamma_dist_type& y_gamma)
      {
        result_type x = x_gamma(engine);
        return x / (x + y_gamma(engine));
      }
  };

  template <typename CharT, typename RealType>
  std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os,
    const beta_distribution<RealType>& beta)
  {
    os << "~Beta(" << beta.a() << "," << beta.b() << ")";
    return os;
  }

  template <typename CharT, typename RealType>
  std::basic_istream<CharT>& operator>>(std::basic_istream<CharT>& is,
    beta_distribution<RealType>& beta)
  {
    std::string str;
    RealType a, b;
    if (std::getline(is, str, '(') && str == "~Beta" &&
        is >> a && is.get() == ',' && is >> b && is.get() == ')') {
      beta = beta_distribution<RealType>(a, b);
    } else {
      is.setstate(std::ios::failbit);
    }
    return is;
  }

}

Use it like so:

std::random_device rd;
std::mt19937 gen(rd());
sftrabbit::beta_distribution<> beta(2, 2);
for (int i = 0; i < 10000; i++) {
  std::cout << beta(gen) << std::endl;
}

Maybe you can use the code that gsl uses for producing random numbers with the beta distribution. They use a little weird way of produging them, as you have to pass a random number generator to the function, but surely you can get what you need.

Here's the documentation and the web page

Boost "inverse incomplete Beta" is another fast (and simple) way to simulate Betas.

#include <random>
#include <boost/math/special_functions/beta.hpp>
template<typename URNG>
double beta_sample(URNG& engine, double a, double b)
{
  static std::uniform_real_distribution<double> unif(0,1);
  double p = unif(engine);
  return boost::math::ibeta_inv(a, b, p); 
  // Use Boost policies if it's not fast enough
}

Check out the random number generator implementations in NumPy : NumPy distributions source

They are implemented in C, and work very fast.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM