10 #if !defined(EXRANDOM_DISCRETE_NORMAL_DIST_HPP) 11 #define EXRANDOM_DISCRETE_NORMAL_DIST_HPP 1 67 : _mu_num(0), _mu_den(1), _sigma_num(1), _sigma_den(1) {}
78 { param_init(mu, 1, sigma, 1); }
95 int mu_num()
const {
return _mu_num; }
99 int mu_den()
const {
return _mu_den; }
119 p1._mu_num == p2._mu_num &&
120 p1._mu_den == p2._mu_den &&
121 p1._sigma_num == p2._sigma_num &&
122 p1._sigma_den == p2._sigma_den;
133 const auto flags = os.flags();
134 os.flags(std::ios::dec);
149 const auto flags = is.flags();
150 is.flags(std::ios::dec | std::ios::skipws);
158 int _mu_num, _mu_den, _sigma_num, _sigma_den;
162 mu_num > std::numeric_limits<int>::min()))
163 throw std::runtime_error(
"discrete_normal_dist: need sigma > 0");
180 : _D(D), _y(D), _z(D), _j(D), _param()
190 : _D(D), _y(D), _z(D), _j(D), _param(p)
203 : _D(D), _y(D), _z(D), _j(D), _param(mu, sigma)
235 : _D(D), _y(D), _z(D), _j(D)
263 template<
typename Generator>
267 k = S(k);
if (k < 0)
continue;
289 int s = j.
init(g,2)(g) ? -1 : 1;
290 long long xn0 = _sig * k + s * _mu;
291 int i0 = int(iceil(xn0, _d));
300 int h = k;
while (h-- && E(g, xn0, j)) {};
301 if (!(h < 0))
continue;
302 if (!B(g, xn0, j))
continue;
316 template<
typename Generator>
328 const param_type&
param()
const {
return _param; }
336 static const int b = digit_gen::base;
339 static_assert(digit_gen::bits <= 24,
"base must be in [2,2^24]");
346 long long _sig, _mu, _d;
349 static long long iceil(
long long n,
long long d)
350 {
long long k = n / d;
return k + (k * d < n ? 1 : 0); }
353 static int gcd(
int u,
int v) {
354 u = std::abs(u); v = std::abs(v);
355 while (v > 0) {
int r = u % v; u = v; v = r; }
360 static const long long maxll = std::numeric_limits<long long>::max();
361 static const int maxint = std::numeric_limits<int>::max();
362 _imu = int(_param.mu_num() / _param.mu_den());
363 int fmu_num = _param.mu_num() - _imu * _param.mu_den();
364 _isig = int(iceil(_param.sigma_num(), _param.sigma_den()));
365 long long l = gcd(_param.sigma_den(), _param.mu_den());
366 if (!( _param.mu_den() / l <= maxll / _param.sigma_num() &&
367 std::abs(fmu_num) <= maxll / (_param.sigma_den() / l) &&
368 _param.mu_den() / l <= maxll / _param.sigma_den() ))
369 throw std::runtime_error(
"discrete_normal_dist: sigma or mu overflow");
370 _sig = _param.sigma_num() * (_param.mu_den() / l);
371 _mu = fmu_num * (_param.sigma_den() / l);
372 _d = _param.sigma_den() * (_param.mu_den() / l);
375 if (!(_isig <= maxll / _d))
376 throw std::runtime_error(
"discrete_normal_dist: sigma or mu overflow");
381 if (!(_isig <= maxint / kmax))
382 throw std::runtime_error(
"discrete_normal_dist: possible overflow a");
383 if (!(std::abs(_imu) <= maxint - _isig * kmax))
384 throw std::runtime_error(
"discrete_normal_dist: possible overflow b");
394 if (!((std::max)(2LL, _sig) <= maxll / (b * kmax)))
395 throw std::runtime_error(
"discrete_normal_dist: possible overflow c");
399 template<
typename Generator>
400 bool H(Generator& g) {
401 if (!_y.
init().less_than_half(g))
return true;
403 if (!_z.
init().less_than(g, _y))
return false;
404 if (!_y.
init().less_than(g, _z))
return true;
409 template<
typename Generator>
411 {
int n = 0;
while (H(g)) ++n;
return n; }
415 for (
int k = 0, k2 = 0; k2 <= n; ++k, k2 += 2*k - 1) {
417 if (n == k2)
return k;
424 template<
typename Generator>
425 bool E(Generator& g,
long long xn0, i_rand<digit_gen>& j) {
426 if (!_y.
init().less_than(g, xn0, _d, _sig, j))
return true;
428 if (!_z.
init().less_than(g, _y))
return false;
429 if (!_y.
init().less_than(g, _z))
return true;
435 template<
typename Generator>
436 bool B(Generator& g,
long long xn0,
437 i_rand<digit_gen>& j) {
440 if (_z.
init().less_than_half(g))
break;
444 if (!_y.
init().less_than(g, xn0, _d, _sig, j))
break;
454 #endif // EXRANDOM_DISCRETE_NORMAL_DIST_HPP bool greater_than(Generator &g, long long m, long long n=1)
friend std::istream & operator>>(std::istream &is, param_type &x)
discrete_normal_dist(digit_gen &D, int mu_num, int sigma_num, int den)
discrete_normal_dist(digit_gen &D, const param_type &p)
discrete_normal_dist(digit_gen &D, int mu_num, int mu_den, int sigma_num, int sigma_den)
param_type(int mu_num, int sigma_num, int den)
bool less_than(Generator &g, u_rand &t)
discrete_normal_dist(digit_gen &D, int mu, int sigma)
A class to sample integers [0,m).
Partially sample exactly from the discrete normal distribution.
digit_gen & digit_generator() const
const param_type & param() const
param_type(int mu_num, int mu_den, int sigma_num, int sigma_den)
friend std::ostream & operator<<(std::ostream &os, const param_type &x)
param_type(int mu, int sigma)
discrete_normal_dist(digit_gen &D)
Hold the parameters of discrete_normal_dist.
The machinery to handle u-rands, arbitrary precision random deviates.
void generate(Generator &g, i_rand< digit_gen > &j)
i_rand & init(Generator &g, int m)
int operator()(Generator &g)
friend bool operator==(const param_type &p1, const param_type &p2)
bool less_than(Generator &g, long long m, long long n=1)
void init(const param_type ¶m)